1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
<?php
namespace Studip\Cli\Commands\Checks;
use Config;
use DirectoryIterator;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
use RegexIterator;
use Studip\Cli\Commands\AbstractCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
final class GlobalizedConfig extends AbstractCommand
{
protected static $defaultName = 'check:globalized-config';
protected function configure(): void
{
$this->setDescription(
'<href=https://develop.studip.de/trac/ticket/5671>TIC 5671</> scanner - Globalized config'
);
$this->setHelp(
'Scans files for occurences of globalized config items (see <href=https://develop.studip.de/trac/ticket/5671>ticket 5671</> for more info)'
);
$this->addOption('filenames', 'f', InputOption::VALUE_NONE, 'Display filenames only (excludes -m and -o)');
$this->addOption('matches', 'm', InputOption::VALUE_NONE, 'Show matched config variables');
$this->addOption(
'recursive',
'r',
InputOption::VALUE_NONE | InputOption::VALUE_NEGATABLE,
'Do not scan recursively into subfolders'
);
$this->addOption('occurences', 'o', InputOption::VALUE_NONE, 'Show occurences in files');
$this->addArgument(
'folder',
InputArgument::IS_ARRAY | InputArgument::OPTIONAL,
'Folder(s) to scan (pass the special value of "plugins" to scan the plugin folder)',
[$GLOBALS['STUDIP_BASE_PATH']]
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$only_filenames = (bool) $input->getOption('filenames');
$show_occurences = !$only_filenames && ($output->isVerbose() || $input->getOption('occurences'));
$show_matches = !$only_filenames && ($show_occurences || $input->getOption('matches'));
$recursive = $input->getOption('recursive') ?? true;
$folders = $input->getArgument('folder');
foreach ($folders as $index => $folder) {
if ($folder === 'plugins') {
$folders[$index] = $GLOBALS['STUDIP_BASE_PATH'] . '/public/plugins_packages/';
}
}
$folders = array_unique($folders);
$config = Config::get()->getFields('global');
$quoted = array_map(function ($item) {
return preg_quote($item, '/');
}, $config);
$regexp = '/\$(?:GLOBALS\[["\']?)?(' . implode('|', $quoted) . ')\b/S';
foreach ($folders as $folder) {
if (!file_exists($folder) || !is_dir($folder)) {
$output->writeln(
"Skipping non-folder argument <fg=red>{$folder}</>",
OutputInterface::VERBOSITY_VERBOSE
);
continue;
}
$output->writeln("Scanning {$folder}", OutputInterface::VERBOSITY_VERBOSE);
foreach ($this->getFolderIterator($folder, $recursive, ['php', 'tpl', 'inc']) as $file) {
$filename = $file->getPathName();
$contents = file_get_contents($filename);
$output->writeln(
sprintf(
'Check <fg=magenta>%s</>',
$this->relativeFilePath($filename)
),
OutputInterface::VERBOSITY_VERBOSE
);
if ($matched = preg_match_all($regexp, $contents, $matches)) {
if ($only_filenames) {
$output->writeln($filename);
} else {
$output->writeln(
sprintf(
'%u matched variable(s) in <fg=green;options=bold>%s</>',
$matched,
$this->shorten($filename)
)
);
if ($show_matches) {
$variables = array_unique($matches[1]);
foreach ($variables as $variable) {
$output->writeln("> <fg=cyan>{$variable}</>");
if ($show_occurences) {
$output->writeln($this->highlight($contents, $variable));
}
}
}
}
}
}
}
return Command::SUCCESS;
}
private function highlight(string $content, string $variable): string
{
$lines = explode("\n", $content);
$result = [];
foreach ($lines as $index => $line) {
if (mb_strpos($line, $variable) === false) {
continue;
}
$result[$index + 1] = $line;
}
if (!$result) {
return '';
}
$max = max(array_map('mb_strlen', array_keys($result)));
foreach ($result as $index => $line) {
$result[$index] = sprintf(
"<fg=yellow>:%0{$max}u:</> %s",
$index,
str_replace($variable, "<fg=black;bg=yellow>{$variable}</>", $line)
);
}
return implode("\n", $result);
}
}
|