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 | namespace rtens\domin\delivery\cli; |
||
3 | |||
4 | use rtens\domin\Action; |
||
5 | use rtens\domin\ActionRegistry; |
||
6 | use rtens\domin\delivery\cli\fields\ArrayField; |
||
7 | use rtens\domin\delivery\cli\fields\BooleanField; |
||
8 | use rtens\domin\delivery\cli\fields\DateIntervalField; |
||
9 | use rtens\domin\delivery\cli\fields\DateTimeField; |
||
10 | use rtens\domin\delivery\cli\fields\EnumerationField; |
||
11 | use rtens\domin\delivery\cli\fields\FileField; |
||
12 | use rtens\domin\delivery\cli\fields\HtmlField; |
||
13 | use rtens\domin\delivery\cli\fields\IdentifierField; |
||
14 | use rtens\domin\delivery\cli\fields\MultiField; |
||
15 | use rtens\domin\delivery\cli\fields\NullableField; |
||
16 | use rtens\domin\delivery\cli\fields\ObjectField; |
||
17 | use rtens\domin\delivery\cli\fields\PrimitiveField; |
||
18 | use rtens\domin\delivery\cli\fields\RangeField; |
||
19 | use rtens\domin\delivery\cli\renderers\ArrayRenderer; |
||
20 | use rtens\domin\delivery\cli\renderers\BooleanRenderer; |
||
21 | use rtens\domin\delivery\cli\renderers\ChartRenderer; |
||
22 | use rtens\domin\delivery\cli\renderers\DateIntervalRenderer; |
||
23 | use rtens\domin\delivery\cli\renderers\DateTimeRenderer; |
||
24 | use rtens\domin\delivery\cli\renderers\DelayedOutputRenderer; |
||
25 | use rtens\domin\delivery\cli\renderers\FileRenderer; |
||
26 | use rtens\domin\delivery\cli\renderers\HtmlRenderer; |
||
27 | use rtens\domin\delivery\cli\renderers\IdentifierRenderer; |
||
28 | use rtens\domin\delivery\cli\renderers\ObjectRenderer; |
||
29 | use rtens\domin\delivery\cli\renderers\PrimitiveRenderer; |
||
30 | use rtens\domin\delivery\cli\renderers\tables\DataTableRenderer; |
||
31 | use rtens\domin\delivery\cli\renderers\tables\ObjectTableRenderer; |
||
32 | use rtens\domin\delivery\cli\renderers\tables\TableRenderer; |
||
33 | use rtens\domin\delivery\FieldRegistry; |
||
34 | use rtens\domin\delivery\ParameterReader; |
||
35 | use rtens\domin\delivery\RendererRegistry; |
||
36 | use rtens\domin\execution\access\AccessControl; |
||
37 | use rtens\domin\execution\ExecutionResult; |
||
38 | use rtens\domin\execution\FailedResult; |
||
39 | use rtens\domin\execution\MissingParametersResult; |
||
40 | use rtens\domin\execution\NoResult; |
||
41 | use rtens\domin\execution\NotPermittedResult; |
||
42 | use rtens\domin\execution\RedirectResult; |
||
43 | use rtens\domin\execution\ValueResult; |
||
44 | use rtens\domin\Executor; |
||
45 | use rtens\domin\reflection\CommentParser; |
||
46 | use rtens\domin\reflection\types\TypeFactory; |
||
47 | use watoki\factory\Factory; |
||
48 | |||
49 | class CliApplication { |
||
50 | |||
51 | const INTERACTIVE_MODE = '!'; |
||
52 | |||
53 | const OK = 0; |
||
54 | const ERROR = 1; |
||
55 | |||
56 | /** @var Factory */ |
||
57 | public $factory; |
||
58 | |||
59 | /** @var ActionRegistry */ |
||
60 | public $actions; |
||
61 | |||
62 | /** @var FieldRegistry */ |
||
63 | public $fields; |
||
64 | |||
65 | /** @var RendererRegistry */ |
||
66 | public $renderers; |
||
67 | |||
68 | /** @var TypeFactory */ |
||
69 | public $types; |
||
70 | |||
71 | /** @var CommentParser */ |
||
72 | public $parser; |
||
73 | |||
74 | /** @var AccessControl */ |
||
75 | public $access; |
||
76 | |||
77 | /** |
||
78 | * @param Factory $factory <- |
||
79 | * @param ActionRegistry $actions <- |
||
80 | * @param FieldRegistry $fields <- |
||
81 | * @param RendererRegistry $renderers <- |
||
82 | * @param TypeFactory $types <- |
||
83 | * @param CommentParser $parser <- |
||
84 | * @param AccessControl $access <- |
||
85 | */ |
||
86 | public function __construct(Factory $factory, ActionRegistry $actions, FieldRegistry $fields, |
||
87 | RendererRegistry $renderers, TypeFactory $types, CommentParser $parser, |
||
88 | AccessControl $access) { |
||
89 | $this->factory = $factory; |
||
90 | |||
91 | $this->actions = $actions; |
||
92 | $this->fields = $fields; |
||
93 | $this->renderers = $renderers; |
||
94 | $this->types = $types; |
||
95 | $this->parser = $parser; |
||
96 | $this->access = $access; |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * @param callable $callback Receives the CliApplication instance |
||
101 | * @param null|Factory $factory |
||
102 | * @return Factory |
||
103 | */ |
||
104 | public static function init(callable $callback, Factory $factory = null) { |
||
105 | $factory = $factory ?: new Factory(); |
||
106 | $callback($factory->setSingleton($factory->getInstance(self::class))); |
||
107 | return $factory; |
||
108 | } |
||
109 | |||
110 | public static function run(Factory $factory, Console $console = null) { |
||
111 | global $argv; |
||
0 ignored issues
–
show
|
|||
112 | |||
113 | /** @var self $app */ |
||
114 | $app = $factory->getInstance(self::class); |
||
115 | return $app->doRun($console ?: new Console($argv)); |
||
116 | } |
||
117 | |||
118 | private function doRun(Console $console) { |
||
119 | $outFile = null; |
||
120 | |||
121 | if ($console->getArguments()) { |
||
122 | if ($console->getArguments()[0] == self::INTERACTIVE_MODE) { |
||
123 | $outFile = $console->getOption('out', null); |
||
124 | |||
125 | $actionId = $this->selectAction($console); |
||
126 | $reader = new InteractiveCliParameterReader($this->fields, $console); |
||
127 | |||
128 | $this->printActionHeader($console, $actionId); |
||
129 | } else { |
||
130 | $actionId = $console->getArguments()[0]; |
||
131 | $reader = new CliParameterReader($console); |
||
132 | } |
||
133 | } else { |
||
134 | $this->printUsage($console); |
||
135 | $this->printActions($console); |
||
136 | return self::OK; |
||
137 | } |
||
138 | |||
139 | $this->registerFields($reader); |
||
140 | $this->registerRenderers(); |
||
141 | |||
142 | $executor = new Executor($this->actions, $this->fields, $reader, $this->access); |
||
143 | return $this->printResult($console, $executor->execute($actionId), $outFile); |
||
144 | } |
||
145 | |||
146 | private function printResult(Console $console, ExecutionResult $result, $outFile) { |
||
147 | if ($result instanceof ValueResult) { |
||
148 | $value = $result->getValue(); |
||
149 | $rendered = (string)$this->renderers->getRenderer($value)->render($value); |
||
150 | |||
151 | if ($outFile) { |
||
152 | file_put_contents($outFile, $rendered); |
||
153 | $console->writeLine("Output written to [$outFile]"); |
||
154 | } else { |
||
155 | $console->writeLine($rendered); |
||
156 | } |
||
157 | return self::OK; |
||
158 | |||
159 | } else if ($result instanceof MissingParametersResult) { |
||
160 | $console->writeLine(); |
||
161 | $console->writeLine("Missing parameters!"); |
||
162 | foreach ($result->getMissingNames() as $missing) { |
||
163 | $console->writeLine(' ' . $missing . ': ' . $result->getException($missing)->getMessage()); |
||
164 | } |
||
165 | return self::ERROR; |
||
166 | |||
167 | } else if ($result instanceof NotPermittedResult) { |
||
168 | $console->writeLine('Permission denied'); |
||
169 | return self::ERROR; |
||
170 | |||
171 | } else if ($result instanceof FailedResult) { |
||
172 | $console->writeLine("Error: " . $result->getMessage()); |
||
173 | |||
174 | $exception = $result->getException(); |
||
175 | $console->error( |
||
176 | get_class($exception) . ': ' . $exception->getMessage() . ' ' . |
||
177 | '[' . $exception->getFile() . ':' . $exception->getLine() . ']' . "\n" . |
||
178 | $exception->getTraceAsString() |
||
179 | ); |
||
180 | return $exception->getCode() ?: self::ERROR; |
||
181 | |||
182 | } else if ($result instanceof NoResult || $result instanceof RedirectResult) { |
||
183 | return self::OK; |
||
184 | |||
185 | } else { |
||
186 | $console->writeLine('Cannot print [' . (new \ReflectionClass($result))->getShortName() . ']'); |
||
187 | return self::OK; |
||
188 | } |
||
189 | } |
||
190 | |||
191 | private function selectAction(Console $console) { |
||
192 | $console->writeLine(); |
||
193 | $console->writeLine('Available Actions'); |
||
194 | $console->writeLine('~~~~~~~~~~~~~~~~~'); |
||
195 | |||
196 | $i = 1; |
||
197 | $actionIds = []; |
||
198 | View Code Duplication | foreach ($this->actions->getAllActions() as $id => $action) { |
|
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. ![]() |
|||
199 | $console->writeLine($i++ . " - " . $action->caption() . $this->shortDescription($action)); |
||
200 | $actionIds[] = $id; |
||
201 | } |
||
202 | |||
203 | $console->writeLine(); |
||
204 | $actionIndex = $console->read('Action: '); |
||
205 | |||
206 | return $actionIds[$actionIndex - 1]; |
||
207 | } |
||
208 | |||
209 | private function printActionHeader(Console $console, $actionId) { |
||
210 | $action = $this->actions->getAction($actionId); |
||
211 | $console->writeLine(); |
||
212 | $console->writeLine($action->caption()); |
||
213 | $console->writeLine(str_repeat('~', strlen($action->caption()))); |
||
214 | $console->writeLine(); |
||
215 | |||
216 | if ($action->description()) { |
||
0 ignored issues
–
show
The expression
$action->description() of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
217 | $console->writeLine($action->description()); |
||
218 | $console->writeLine(); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | private function printUsage(Console $console) { |
||
223 | $console->writeLine(); |
||
224 | |||
225 | $console->writeLine("Interactive mode: php {$console->getScriptName()} !"); |
||
226 | $console->writeLine("Execute Action: php {$console->getScriptName()} <actionId> --<parameterName> <parameterValue> ..."); |
||
227 | $console->writeLine(); |
||
228 | } |
||
229 | |||
230 | private function printActions(Console $console) { |
||
231 | $console->writeLine('Available Actions'); |
||
232 | $console->writeLine('~~~~~~~~~~~~~~~~~'); |
||
233 | |||
234 | View Code Duplication | foreach ($this->actions->getAllActions() as $id => $action) { |
|
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. ![]() |
|||
235 | $console->writeLine($id . ' - ' . $action->caption() . $this->shortDescription($action)); |
||
236 | } |
||
237 | $console->writeLine(); |
||
238 | } |
||
239 | |||
240 | private function registerFields(ParameterReader $reader) { |
||
241 | $this->fields->add(new PrimitiveField()); |
||
242 | $this->fields->add(new RangeField()); |
||
243 | $this->fields->add(new BooleanField()); |
||
244 | $this->fields->add(new FileField()); |
||
245 | $this->fields->add(new HtmlField($reader)); |
||
246 | $this->fields->add(new DateTimeField()); |
||
247 | $this->fields->add(new DateIntervalField()); |
||
248 | $this->fields->add(new ArrayField($this->fields, $reader)); |
||
249 | $this->fields->add(new NullableField($this->fields, $reader)); |
||
250 | $this->fields->add(new ObjectField($this->types, $this->fields, $reader)); |
||
251 | $this->fields->add(new MultiField($this->fields, $reader)); |
||
252 | $this->fields->add(new IdentifierField($this->fields)); |
||
253 | $this->fields->add(new EnumerationField($this->fields)); |
||
254 | } |
||
255 | |||
256 | private function registerRenderers() { |
||
257 | $this->renderers->add(new BooleanRenderer()); |
||
258 | $this->renderers->add(new PrimitiveRenderer()); |
||
259 | $this->renderers->add(new DateTimeRenderer()); |
||
260 | $this->renderers->add(new DateIntervalRenderer()); |
||
261 | $this->renderers->add(new HtmlRenderer()); |
||
262 | $this->renderers->add(new IdentifierRenderer()); |
||
263 | $this->renderers->add(new FileRenderer('')); |
||
264 | $this->renderers->add(new DelayedOutputRenderer()); |
||
265 | $this->renderers->add(new ObjectTableRenderer($this->renderers)); |
||
266 | $this->renderers->add(new DataTableRenderer($this->renderers)); |
||
267 | $this->renderers->add(new TableRenderer($this->renderers)); |
||
268 | $this->renderers->add(new ChartRenderer($this->renderers)); |
||
269 | $this->renderers->add(new ArrayRenderer($this->renderers)); |
||
270 | $this->renderers->add(new ObjectRenderer($this->renderers, $this->types)); |
||
271 | } |
||
272 | |||
273 | private function shortDescription(Action $action) { |
||
274 | $description = $this->parser->shorten($action->description()); |
||
275 | return $description ? " ($description)" : ''; |
||
276 | } |
||
277 | } |
||
278 |
Instead of relying on
global
state, we recommend one of these alternatives:1. Pass all data via parameters
2. Create a class that maintains your state