This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | * This file is part of the webmozart/console package. |
||
5 | * |
||
6 | * (c) Bernhard Schussek <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Webmozart\Console\Resolver; |
||
13 | |||
14 | use Webmozart\Console\Api\Application\Application; |
||
15 | use Webmozart\Console\Api\Args\RawArgs; |
||
16 | use Webmozart\Console\Api\Command\Command; |
||
17 | use Webmozart\Console\Api\Command\CommandCollection; |
||
18 | use Webmozart\Console\Api\Config\OptionCommandConfig; |
||
19 | use Webmozart\Console\Api\Resolver\CannotResolveCommandException; |
||
20 | use Webmozart\Console\Api\Resolver\CommandResolver; |
||
21 | use Webmozart\Console\Api\Resolver\ResolvedCommand; |
||
22 | |||
23 | /** |
||
24 | * Parses the raw console arguments for the command to execute. |
||
25 | * |
||
26 | * @since 1.0 |
||
27 | * |
||
28 | * @author Bernhard Schussek <[email protected]> |
||
29 | */ |
||
30 | class DefaultResolver implements CommandResolver |
||
31 | { |
||
32 | /** |
||
33 | * {@inheritdoc} |
||
34 | */ |
||
35 | 217 | public function resolveCommand(RawArgs $args, Application $application) |
|
36 | { |
||
37 | 217 | $tokens = $args->getTokens(); |
|
38 | 217 | $namedCommands = $application->getNamedCommands(); |
|
39 | |||
40 | 217 | $argumentsToTest = $this->getArgumentsToTest($tokens); |
|
41 | 217 | $optionsToTest = $this->getOptionsToTest($tokens); |
|
42 | |||
43 | // Try to find a command for the passed arguments and options. |
||
44 | 217 | if ($result = $this->processArguments($args, $namedCommands, $argumentsToTest, $optionsToTest)) { |
|
45 | 199 | return $this->createResolvedCommand($result); |
|
46 | } |
||
47 | |||
48 | // If arguments were passed, we did not find the matching command. |
||
49 | 18 | if ($argumentsToTest) { |
|
0 ignored issues
–
show
|
|||
50 | 1 | throw CannotResolveCommandException::nameNotFound(reset($argumentsToTest), $namedCommands); |
|
51 | } |
||
52 | |||
53 | // If no arguments were passed, run the application's default command. |
||
54 | 17 | if ($result = $this->processDefaultCommands($args, $application->getDefaultCommands())) { |
|
55 | 17 | return $this->createResolvedCommand($result); |
|
56 | } |
||
57 | |||
58 | // No default command is configured. |
||
59 | throw CannotResolveCommandException::noDefaultCommand(); |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * @param RawArgs $args |
||
64 | * @param CommandCollection $namedCommands |
||
65 | * @param string[] $argumentsToTest |
||
66 | * @param string[] $optionsToTest |
||
67 | * |
||
68 | * @return ResolveResult |
||
0 ignored issues
–
show
|
|||
69 | */ |
||
70 | 217 | private function processArguments(RawArgs $args, CommandCollection $namedCommands, array $argumentsToTest, array $optionsToTest) |
|
71 | { |
||
72 | 217 | $currentCommand = null; |
|
73 | |||
74 | // Parse the arguments for command names until we fail to find a |
||
75 | // matching command |
||
76 | 217 | View Code Duplication | foreach ($argumentsToTest as $name) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
77 | 200 | if (!$namedCommands->contains($name)) { |
|
78 | 16 | break; |
|
79 | } |
||
80 | |||
81 | 199 | $nextCommand = $namedCommands->get($name); |
|
82 | |||
83 | 199 | if ($nextCommand->getConfig() instanceof OptionCommandConfig) { |
|
84 | break; |
||
85 | } |
||
86 | |||
87 | 199 | $currentCommand = $nextCommand; |
|
88 | 199 | $namedCommands = $currentCommand->getNamedSubCommands(); |
|
89 | } |
||
90 | |||
91 | 217 | if (!$currentCommand) { |
|
92 | 18 | return null; |
|
93 | } |
||
94 | |||
95 | 199 | return $this->processOptions($args, $currentCommand, $optionsToTest); |
|
96 | } |
||
97 | |||
98 | /** |
||
99 | * @param RawArgs $args |
||
100 | * @param Command $currentCommand |
||
101 | * @param string[] $optionsToTest |
||
102 | * |
||
103 | * @return ResolveResult |
||
104 | */ |
||
105 | 199 | private function processOptions(RawArgs $args, Command $currentCommand, array $optionsToTest) |
|
106 | { |
||
107 | 199 | View Code Duplication | foreach ($optionsToTest as $option) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
108 | 142 | $commands = $currentCommand->getNamedSubCommands(); |
|
109 | |||
110 | 142 | if (!$commands->contains($option)) { |
|
111 | 131 | continue; |
|
112 | } |
||
113 | |||
114 | 45 | $nextCommand = $commands->get($option); |
|
115 | |||
116 | 45 | if (!$nextCommand->getConfig() instanceof OptionCommandConfig) { |
|
117 | break; |
||
118 | } |
||
119 | |||
120 | 45 | $currentCommand = $nextCommand; |
|
121 | } |
||
122 | |||
123 | 199 | return $this->processDefaultSubCommands($args, $currentCommand); |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * @param RawArgs $args |
||
128 | * @param Command $currentCommand |
||
129 | * |
||
130 | * @return ResolveResult |
||
131 | */ |
||
132 | 199 | private function processDefaultSubCommands(RawArgs $args, Command $currentCommand) |
|
133 | { |
||
134 | 199 | if ($result = $this->processDefaultCommands($args, $currentCommand->getDefaultSubCommands())) { |
|
135 | 42 | return $result; |
|
136 | } |
||
137 | |||
138 | // No default commands, return the current command |
||
139 | 157 | return new ResolveResult($currentCommand, $args); |
|
140 | } |
||
141 | |||
142 | /** |
||
143 | * @param RawArgs $args |
||
144 | * @param CommandCollection $defaultCommands |
||
145 | * |
||
146 | * @return ResolveResult |
||
0 ignored issues
–
show
|
|||
147 | */ |
||
148 | 216 | private function processDefaultCommands(RawArgs $args, CommandCollection $defaultCommands) |
|
149 | { |
||
150 | 216 | $firstResult = null; |
|
151 | |||
152 | 216 | foreach ($defaultCommands as $defaultCommand) { |
|
153 | 59 | $resolvedCommand = new ResolveResult($defaultCommand, $args); |
|
154 | |||
155 | 59 | if ($resolvedCommand->isParsable()) { |
|
156 | 58 | return $resolvedCommand; |
|
157 | } |
||
158 | |||
159 | 7 | if (!$firstResult) { |
|
160 | 7 | $firstResult = $resolvedCommand; |
|
161 | } |
||
162 | } |
||
163 | |||
164 | // Return the first default command if one was found |
||
165 | 158 | return $firstResult; |
|
166 | } |
||
167 | |||
168 | 217 | private function getArgumentsToTest(array &$tokens) |
|
169 | { |
||
170 | 217 | $argumentsToTest = array(); |
|
171 | |||
172 | 217 | for (; null !== key($tokens); next($tokens)) { |
|
173 | 214 | $token = current($tokens); |
|
174 | |||
175 | // "--" stops argument parsing |
||
176 | 214 | if ('--' === $token) { |
|
177 | 3 | break; |
|
178 | } |
||
179 | |||
180 | // Stop argument parsing when we reach the first option. |
||
181 | |||
182 | // Command names must be passed before any option. The reason |
||
183 | // is that we cannot determine whether an argument after an |
||
184 | // option is the value of that option or an argument by itself |
||
185 | // without getting the input definition of the corresponding |
||
186 | // command first. |
||
187 | |||
188 | // For example, in the command "server -f add" we don't know |
||
189 | // whether "add" is the value of the "-f" option or an argument. |
||
190 | // Hence we stop argument parsing after "-f" and assume that |
||
191 | // "server" (or "server -f") is the command to execute. |
||
192 | 214 | if (isset($token[0]) && '-' === $token[0]) { |
|
193 | 173 | break; |
|
194 | } |
||
195 | |||
196 | 200 | $argumentsToTest[] = $token; |
|
197 | } |
||
198 | |||
199 | 217 | return $argumentsToTest; |
|
200 | } |
||
201 | |||
202 | 217 | private function getOptionsToTest(array &$tokens) |
|
203 | { |
||
204 | 217 | $optionsToTest = array(); |
|
205 | |||
206 | 217 | for (; null !== key($tokens); next($tokens)) { |
|
207 | 176 | $token = current($tokens); |
|
208 | |||
209 | // "--" stops option parsing |
||
210 | 176 | if ('--' === $token) { |
|
211 | 3 | break; |
|
212 | } |
||
213 | |||
214 | 173 | if (isset($token[0]) && '-' === $token[0]) { |
|
215 | 173 | if ('--' === substr($token, 0, 2) && strlen($token) > 2) { |
|
216 | 98 | $optionsToTest[] = substr($token, 2); |
|
217 | 97 | } elseif (2 === strlen($token)) { |
|
218 | 75 | $optionsToTest[] = substr($token, 1); |
|
219 | } |
||
220 | |||
221 | 173 | continue; |
|
222 | } |
||
223 | } |
||
224 | |||
225 | 217 | return $optionsToTest; |
|
226 | } |
||
227 | |||
228 | 216 | private function createResolvedCommand(ResolveResult $result) |
|
229 | { |
||
230 | 216 | if (!$result->isParsable()) { |
|
231 | 1 | throw $result->getParseError(); |
|
232 | } |
||
233 | |||
234 | 215 | return new ResolvedCommand($result->getCommand(), $result->getParsedArgs()); |
|
235 | } |
||
236 | } |
||
237 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.