Server IP : 184.154.167.98 / Your IP : 18.222.179.239 Web Server : Apache System : Linux pink.dnsnetservice.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 User : puertode ( 1767) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/puertode/public_html/mesa/setup/test/tests/ |
Upload File : |
<?php require_once('class.test.php'); class SourceAnalyzer extends Test { static $super_globals = array( '$_SERVER'=>1, '$_FILES'=>1, '$_SESSION'=>1, '$_GET'=>1, '$_POST'=>1, '$_REQUEST'=>1, '$_ENV'=>1, '$_COOKIE'=>1); var $bugs = array(); var $globals = array(); var $file = ''; function __construct($source) { $this->tokens = token_get_all(file_get_contents($source)); $this->file = $source; } function parseFile() { $this->checkVariableUsage( array('line'=>array(0, $this->file), 'name'=>'(main)'), array(), 1); } function traverseClass($line) { $class = array('line'=>$line); $token = false; $blocks = 0; $func_options = array('allow_this'=>true); while (list($i,$token) = [key($this->tokens), current($this->tokens)]) { next($this->tokens); if ($token === false) break; switch ($token[0]) { case '{': $blocks++; break; case '}': if (--$blocks == 0) return; break; case T_STRING: if (!isset($class['name'])) $class['name'] = $token[1]; break; case T_FUNCTION: $this->traverseFunction( array($token[2], $line[1]), $func_options); // Continue to reset $func_options case ';': // Reset function options $func_options = array('allow_this'=>true); break; case T_STATIC: $func_options['allow_this'] = false; break; case T_VAR: // var $variable // used inside classes to define instance variables while ($token = current($this->tokens)) { next($this->tokens); if (is_array($token) && $token[0] == T_VARIABLE) // TODO: Add this to some class context in the // future to support indefined access to $this->blah break; } break; } } } function traverseFunction($line=0, $options=array()) { // Scan for function name $function = array('line'=>$line, 'name'=>'(inline)'); $token = false; $scope = array(); while ($token != "{") { $token = current($this->tokens); next($this->tokens); switch ($token[0]) { case T_WHITESPACE: continue 2; case T_STRING: $function['name'] = $token[1]; break; case T_VARIABLE: $scope[$token[1]] = 1; break; case ';': // Abstract function -- no body will follow return; } } // Start inside a block -- we've already consumed the { $this->checkVariableUsage($function, $scope, 1, $options); } function checkVariableUsage($function, $scope=array(), $blocks=0, $options=array()) { // Merge in defaults to the options array $options = array_merge(array( 'allow_this' => false, ), $options); // Unpack function[line][file] if set if (is_array($function['line'])) $function['file'] = $function['line'][1]; while (list($i,$token) = [key($this->tokens), current($this->tokens)]) { next($this->tokens); if ($token === false) break; // Check variable usage and for nested blocks switch ($token[0]) { case '{': $blocks++; break; case '}': if (--$blocks == 0) return $scope; break; case T_VARIABLE: // Look-ahead for assignment $assignment = false; while ($next = @$this->tokens[++$i]) if (!is_array($next) || $next[0] != T_WHITESPACE) break; switch ($next[0]) { case '=': // For assignment, check if the variable is explictly // assigned to NULL. If so, treat the assignment as an // unset() while ($next = @$this->tokens[++$i]) if (!is_array($next) || $next[0] != T_WHITESPACE) break; if (is_array($next) && strcasecmp('NULL', $next[1]) === 0) { $scope[$token[1]] = 'null'; $assignment = true; break; } case T_AND_EQUAL: case T_CONCAT_EQUAL: case T_DIV_EQUAL: case T_MINUS_EQUAL: case T_MOD_EQUAL: case T_MUL_EQUAL: case T_OR_EQUAL: case T_PLUS_EQUAL: case T_SL_EQUAL: case T_SR_EQUAL: case T_XOR_EQUAL: $assignment = true; $scope[$token[1]] = 1; break; } if ($assignment) break; if (!isset($scope[$token[1]])) { if ($token[1] == '$this' && $options['allow_this']) { // Always valid in a non-static class method // TODO: Determine if this function is defined in a class break; } elseif (isset(static::$super_globals[$token[1]])) // Super globals are always in scope break; elseif (!isset($function['name']) || $function['name'] == '(main)') // Not in a function. Cowardly continue. // TODO: Recurse into require() statements to // determine if global variables are actually // defined somewhere in the code base break; $this->bugs[] = array( 'type' => 'UNDEF_ACCESS', 'func' => $function['name'], 'line' => array($token[2], $function['file']), 'name' => $token[1], ); } elseif ($scope[$token[1]] == 'null') { // See if the next token is accessing a property of the // object $c = current($this->tokens); switch ($c[0]) { case T_OBJECT_OPERATOR: case T_PAAMAYIM_NEKUDOTAYIM: case '[': $this->bugs[] = array( 'type' => 'MAYBE_UNDEF_ACCESS', 'func' => $function['name'], 'line' => array($token[2], $function['file']), 'name' => $token[1], ); } } break; case T_PAAMAYIM_NEKUDOTAYIM: // Handle static variables $instance::$static $current = current($this->tokens); if ($current[0] == T_VARIABLE) next($this->tokens); break; case T_CLASS: // XXX: PHP does not allow nested classes $this->traverseClass( array($token[2], $function['file'])); break; case T_FUNCTION: // PHP does not automatically nest scopes. Variables // available inside the closure must be explictly defined. // Therefore, there is no need to pass the current scope. // As of PHP 5.4, $this is added to the closure automatically $this->traverseFunction( array($token[2], $function['file']), array('allow_this'=>true)); break; case T_STATIC: $c = current($this->tokens); // (nolint) static::func() or static::$var if ($c[0] == T_PAAMAYIM_NEKUDOTAYIM) break; case T_GLOBAL: while ($token = current($this->tokens)) { next($this->tokens); if (($token == ';') || $token === false) break; elseif (!is_array($token)) continue; elseif ($token[0] == T_VARIABLE) $scope[$token[1]] = 1; } break; case T_FOR: // for ($i=0;...) // Find first semi-colon, variables defined before it should // be added to the current scope while ($token = current($this->tokens)) { next($this->tokens); if (($token == ';') || $token === false) break; elseif (!is_array($token)) continue; elseif ($token[0] == T_VARIABLE) $scope[$token[1]] = 1; } break; case T_FOREACH: // foreach ($blah as $a=>$b) -- add $a, $b to the local // scope $after_as = false; $parens = 0; // Scan for the variables defined for the scope of the // foreach block while ($token = current($this->tokens)) { next($this->tokens); if ($token === false) break; if ($token == '(') $parens++; elseif ($token == ')' && --$parens == 0) break; elseif (!is_array($token)) continue; elseif ($token[0] == T_AS) $after_as = true; elseif ($after_as && $token[0] == T_VARIABLE) // Technically, variables defined in a foreach() // block are still accessible after the completion // of the foreach block $scope[$token[1]] = 1; } break; case T_LIST: // list($a, $b) = ... // Find all variables defined up to the closing parenthesis while ($token = current($this->tokens)) { next($this->tokens); if (($token == ')') || $token === false) break; elseif (!is_array($token)) continue; elseif ($token[0] == T_VARIABLE) $scope[$token[1]] = 1; } break; case T_ISSET: // isset($var) // $var is allowed to be undefined and not be an error. // Consume tokens until close parentheses while ($token = current($this->tokens)) { next($this->tokens); if (($token == ')') || $token === false) break; } break; case T_UNSET: // unset($var) // Var will no longer be in scope while ($token = current($this->tokens)) { next($this->tokens); if (($token == ')') || $token === false) break; elseif (is_array($token) && $token[0] == T_VARIABLE) { // Check for unset($var[key]) -- don't unset anything // Check for unset($this->blah) $next = current($this->tokens); switch ($next[0]) { case '[': case T_OBJECT_OPERATOR: break; default: unset($scope[$token[1]]); } break; } } break; case T_CATCH: // catch (Exception $var) { while ($token = current($this->tokens)) { next($this->tokens); if (($token == '{') || $token === false) break; elseif ($token[0] == T_VARIABLE) $variable = $token[1]; } $scope[$variable] = 1; $scope = $this->checkVariableUsage($function, $scope, 1, $options); // Variable is no longer in scope; however, other variables // defined in the catch {} block remain in scope. // (Technically, the variable is in scope, but we will // consider it bad coding practice to deal with an exception // outisde the catch block unset($scope[$variable]); break; case T_DOLLAR_OPEN_CURLY_BRACES: case T_CURLY_OPEN: // "{$a .. }" // This screws up block detection. We will see another close // brace somewhere along the way $blocks++; break; } } } } ?>