CheckCommand   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 18
c 3
b 0
f 0
lcom 1
cbo 7
dl 0
loc 124
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 8 1
B execute() 0 24 5
A getForbiddenFunctions() 0 17 3
A scanFiles() 0 10 3
B scanForForbiddenFunctions() 0 20 6
1
<?php
2
3
namespace NilPortugues\ForbiddenFunctions\Command;
4
5
use NilPortugues\ForbiddenFunctions\Command\Exceptions\ConfigFileException;
6
use NilPortugues\ForbiddenFunctions\Command\Exceptions\RuntimeException;
7
use NilPortugues\ForbiddenFunctions\Checker\FileSystem;
8
use Symfony\Component\Console\Command\Command;
9
use Symfony\Component\Console\Input\InputArgument;
10
use Symfony\Component\Console\Input\InputInterface;
11
use Symfony\Component\Console\Input\InputOption;
12
use Symfony\Component\Console\Output\OutputInterface;
13
use Symfony\Component\Yaml\Yaml;
14
15
class CheckCommand extends Command
16
{
17
    const COMMAND_NAME = 'check';
18
    const CONFIG_FILE = 'php_forbidden_function.yml';
19
20
    /**
21
     * @var array
22
     */
23
    private static $forbiddenFunctions = [];
24
25
    /**
26
     * @var array
27
     */
28
    private $errors = [];
29
30
    /**
31
     *
32
     */
33
    protected function configure()
34
    {
35
        $this
36
            ->setName(self::COMMAND_NAME)
37
            ->setDescription('Looks into the code using a user-defined list of forbidden function in a given path.')
38
            ->addArgument('check', InputArgument::REQUIRED, 'File Path')
39
            ->addOption('config', '-c', InputOption::VALUE_OPTIONAL, 'Config File', self::CONFIG_FILE);
40
    }
41
42
    /**
43
     * Execute command
44
     *
45
     * @param InputInterface  $input  Input
46
     * @param OutputInterface $output Output
47
     *
48
     * @return \int|\null|void
49
     *
50
     * @throws ConfigFileException
51
     */
52
    protected function execute(InputInterface $input, OutputInterface $output)
53
    {
54
        $path = $input->getArgument('check');
55
        $realPath = realpath($path);
56
        $configFile = $input->getOption('config');
57
58
        if (file_exists($configFile)) {
59
            $this->scanFiles($path, $configFile);
60
61
            if (!empty($this->errors)) {
62
                $output->writeln("\nForbidden functions were found:\n");
63
                foreach($this->errors as $file => $lines) {
64
                    foreach($lines as $line) {
65
                        $output->writeln(sprintf(" - .%s: %s", str_replace($realPath, '', $file), $line));
66
                    }
67
                }
68
                $output->writeln('');
69
                throw new \Exception('Fix your code');
70
            }
71
            return $output->writeln("\nCongratulations! No forbidden functions found.\n");
72
        }
73
74
        throw new ConfigFileException($configFile);
75
    }
76
77
    /**
78
     * @return mixed
79
     */
80
    private function getForbiddenFunctions($file)
81
    {
82
        if (!empty(self::$forbiddenFunctions)) {
83
            return self::$forbiddenFunctions;
84
        }
85
86
        $yaml = new Yaml();
87
        $functions = $yaml->parse($file, true);
88
89
        if (!array_key_exists('forbidden', $functions)) {
90
            throw new RuntimeException();
91
        }
92
        self::$forbiddenFunctions = (array) $functions['forbidden'];
93
94
95
        return self::$forbiddenFunctions;
96
    }
97
98
    /**
99
     * @param $path
100
     * @param $configFile
101
     */
102
    protected function scanFiles($path, $configFile)
103
    {
104
        $fileSystem = new FileSystem();
105
        foreach ($fileSystem->getFilesFromPath($path) as $file) {
106
            $tokens = token_get_all(file_get_contents($file));
107
            foreach($tokens as $token) {
108
                $this->scanForForbiddenFunctions($configFile, $token, $file);
109
            }
110
        }
111
    }
112
113
    /**
114
     * @param $configFile
115
     * @param $token
116
     * @param $file
117
     */
118
    protected function scanForForbiddenFunctions($configFile, $token, $file)
119
    {
120
        if (is_array($token) && count($token) === 3) {
121
            $type = $token[0];
122
            $code = $token[1];
123
            $lineNumber = $token[2];
124
125
            if (\false === in_array($type, [T_COMMENT, T_DOC_COMMENT], \true)) {
126
                foreach ($this->getForbiddenFunctions($configFile) as $function) {
127
                    if (\strtolower($code) === \strtolower($function)) {
128
                        $this->errors[$file][] = \sprintf(
129
                            'Forbidden function \'%s\' found on line %s.',
130
                            $function,
131
                            $lineNumber
132
                        );
133
                    }
134
                }
135
            }
136
        }
137
    }
138
}
139