diff --git a/CHANGELOG.md b/CHANGELOG.md index 8430c28..4976d70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # CHANGE LOG -## v1.1.0 20190424 +## v1.1.0 20190427 - Add function calling stack for visitor - Add some sensitive functions -- Remove a duplicate function `BaseVisitor::isMethod` \ No newline at end of file +- Remove a duplicate function `BaseVisitor::isMethod` +- humanize console output \ No newline at end of file diff --git a/screenshot/1.png b/screenshot/1.png index 21ea9d1..999f678 100644 Binary files a/screenshot/1.png and b/screenshot/1.png differ diff --git a/src/Chip/Alarm.php b/src/Chip/Alarm.php index 957e12c..4c8bcce 100644 --- a/src/Chip/Alarm.php +++ b/src/Chip/Alarm.php @@ -8,6 +8,8 @@ namespace Chip; +use PhpParser\Node; + class Alarm implements \JsonSerializable { /** @@ -26,27 +28,38 @@ class Alarm implements \JsonSerializable */ protected $message; - protected $startLine; - - protected $endLine; - - protected $startPos; + /** + * @var Node $node + */ + protected $node; - protected $endPos; + /** + * @var Node $function + */ + protected $function; - public function __construct(AlarmLevel $level, string $type, string $message, $startLine, $endLine, $startPos, $endPos) + public function __construct(AlarmLevel $level, string $type, string $message, Node $node = null, Node $function = null) { $this->level = $level; $this->message = $message; - $this->startLine = $startLine; - $this->endLine = $endLine; - $this->startPos = $startPos; - $this->endPos = $endPos; + + $this->node = $node; + $this->function = $function; $type = explode('\\', $type); $this->type = end($type); } + protected function getPositions(Node $node) + { + return [ + $node->getStartLine(), + $node->getEndLine(), + $node->getStartFilePos(), + $node->getEndFilePos(), + ]; + } + public function getLevel() { return $this->level; @@ -62,9 +75,19 @@ public function getType() return $this->type; } + public function getNode() + { + return $this->node; + } + + public function getFunction() + { + return $this->function; + } + public function lineRange() { - return [$this->startLine, $this->endLine]; + return [$this->node->getStartLine(), $this->node->getEndLine()]; } public function __toString() diff --git a/src/Chip/Chip.php b/src/Chip/Chip.php index 385a622..7fe9c86 100644 --- a/src/Chip/Chip.php +++ b/src/Chip/Chip.php @@ -109,11 +109,7 @@ public function feed($code) $this->message->putMessage( AlarmLevel::WARNING(), 'InvalidPhpFile', - 'PHP脚本格式错误,可能是Webshell', - $e->getStartLine(), - $e->getEndLine(), - 0, - 0 + 'PHP脚本格式错误,可能是Webshell' ); } diff --git a/src/Chip/Console/Check.php b/src/Chip/Console/Check.php index 9ca8e67..02e5a26 100644 --- a/src/Chip/Console/Check.php +++ b/src/Chip/Console/Check.php @@ -78,9 +78,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $content = $fileobj->getContents(); foreach ($this->checkCode($content) as $alarm) { if ($alarm->getLevel()->getValue() >= AlarmLevel::$level()->getValue()) { - $output->writeln("=========="); + $output->writeln("\n=========="); $this->showAlarm($output, $fileobj->getPathname(), $content, $alarm); - $output->writeln(''); } } } @@ -105,15 +104,35 @@ protected function showAlarm(OutputInterface $output, string $filename, string $ $level = $alarm->getLevel()->getKey(); $message = $alarm->getMessage(); - list($startLine, $endLine) = $alarm->lineRange(); + $output->writeln("\n{$level}:{$filename}\n{$message}", OutputInterface::VERBOSITY_QUIET); + $output->writeln(''); - $arr = array_slice(explode("\n", $code), $startLine - 1, $endLine - $startLine + 1); - $arr = array_map(function ($key, $line) use ($startLine) { - $startKey = $startLine + $key; - return " {$startKey}:{$line}"; - }, array_keys($arr), $arr); - $code = implode("\n", $arr); + $node = $alarm->getNode(); + $function = $alarm->getFunction(); + + if (!$node) { + return $output->writeln($code); + } + + list($nodeStartLine, $nodeEndLine) = [$node->getStartLine(), $node->getEndLine()]; + + if ($function) { + list($functionStartLine, $functionEndLine) = [$function->getStartLine(), $function->getEndLine()]; + $arr = array_slice(explode("\n", $code), $functionStartLine - 1, $functionEndLine - $functionStartLine + 1); + $start = $functionStartLine; + } else { + $arr = array_slice(explode("\n", $code), $nodeStartLine - 1, $nodeEndLine - $nodeStartLine + 1); + $start = $nodeStartLine; + } + + return array_map(function ($key, $line) use ($output, $start, $nodeStartLine, $nodeEndLine) { + $startKey = $start + $key; - $output->writeln("\n{$level}:{$filename}\n{$code}\n{$message}", OutputInterface::VERBOSITY_QUIET); + if ($nodeStartLine <= $startKey && $startKey <= $nodeEndLine) { + $output->writeln("{$startKey}:{$line}"); + } else { + $output->writeln("{$startKey}:{$line}"); + } + }, array_keys($arr), $arr); } } diff --git a/src/Chip/Message.php b/src/Chip/Message.php index 1cfd2e4..c26c4ad 100644 --- a/src/Chip/Message.php +++ b/src/Chip/Message.php @@ -8,53 +8,51 @@ namespace Chip; +use Chip\Tracer\CallStack; use PhpParser\Node; class Message extends \ArrayObject implements \JsonSerializable { - public function __construct() - { - parent::__construct([]); - } + /** + * @var CallStack $callStack + */ + protected $callStack; - protected function getPositions(Node $node) + public function __construct(CallStack $stack) { - return [ - $node->getStartLine(), - $node->getEndLine(), - $node->getStartFilePos(), - $node->getEndFilePos(), - ]; + parent::__construct([]); + $this->callStack = $stack; } - public function putMessage($level, $type, $message, ...$positions) + public function putMessage($level, $type, $message, Node $node = null) { - $this[] = new Alarm($level, $type, $message, ...$positions); + $function = $this->callStack->isEmpty() ? null : $this->callStack->top(); + $this[] = new Alarm($level, $type, $message, $node, $function); } public function info(Node $node, string $type, string $message) { - $this->putMessage(AlarmLevel::INFO(), $type, $message, ...$this->getPositions($node)); + $this->putMessage(AlarmLevel::INFO(), $type, $message, $node); } public function warning(Node $node, string $type, string $message) { - $this->putMessage(AlarmLevel::WARNING(), $type, $message, ...$this->getPositions($node)); + $this->putMessage(AlarmLevel::WARNING(), $type, $message, $node); } public function danger(Node $node, string $type, string $message) { - $this->putMessage(AlarmLevel::DANGER(), $type, $message, ...$this->getPositions($node)); + $this->putMessage(AlarmLevel::DANGER(), $type, $message, $node); } public function critical(Node $node, string $type, string $message) { - $this->putMessage(AlarmLevel::CRITICAL(), $type, $message, ...$this->getPositions($node)); + $this->putMessage(AlarmLevel::CRITICAL(), $type, $message, $node); } public function safe(Node $node, string $type, string $message) { - $this->putMessage(AlarmLevel::SAFE(), $type, $message, ...$this->getPositions($node)); + $this->putMessage(AlarmLevel::SAFE(), $type, $message, $node); } public function jsonSerialize() diff --git a/src/Chip/functions.php b/src/Chip/functions.php index ead4acc..927ce60 100644 --- a/src/Chip/functions.php +++ b/src/Chip/functions.php @@ -19,10 +19,10 @@ function strip_whitespace(string $code) return trim(substr($code, 5)); } -function dump_node(Node $node) +function dump_node(Node $node, $minify = true) { $prettyPrinter = new PrettyPrinter(); $code = $prettyPrinter->prettyPrint([$node]); - return strip_whitespace($code); + return $minify ? strip_whitespace($code) : $code; }