[CLEANUP] Ensure variables initalized and fix code smell
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Controller / CommandLineController.php
1 <?php
2 namespace TYPO3\CMS\Core\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * TYPO3 cli script basis
21 * @deprecated since TYPO3 v8, will be removed in TYPO3 v9, use a custom Command instead
22 */
23 class CommandLineController
24 {
25 /**
26 * Command line arguments, exploded into key => value-array pairs
27 *
28 * @var array
29 */
30 public $cli_args = [];
31
32 /**
33 * @var array
34 */
35 public $cli_options = [
36 ['-s', 'Silent operation, will only output errors and important messages.'],
37 ['--silent', 'Same as -s'],
38 ['-ss', 'Super silent, will not even output errors or important messages.']
39 ];
40
41 /**
42 * @var array
43 */
44 public $cli_help = [
45 'name' => 'CLI base class (overwrite this...)',
46 'synopsis' => '###OPTIONS###',
47 'description' => 'Class with basic functionality for CLI scripts (overwrite this...)',
48 'examples' => 'Give examples...',
49 'options' => '',
50 'license' => 'GNU GPL - free software!',
51 'author' => '[Author name]'
52 ];
53
54 /**
55 * @var resource
56 */
57 public $stdin = null;
58
59 /**
60 * Constructor
61 * Make sure child classes also call this!
62 *
63 * @return void
64 * @deprecated the CommandLineController is deprecated since TYPO3 v8 and will be removed in TYPO3 v9, use a separate CLI Command instead
65 */
66 public function __construct()
67 {
68 GeneralUtility::logDeprecatedFunction();
69 // Loads the cli_args array with command line arguments
70 $this->cli_setArguments($_SERVER['argv']);
71 }
72
73 /**
74 * Finds the arg token (like "-s") in argv and returns the rest of argv from that point on.
75 * This should only be used in special cases since this->cli_args should already be prepared with an index of values!
76 *
77 * @param string $option Option string, eg. "-s
78 * @param array $argv Input argv array
79 * @return array Output argv array with all options AFTER the found option.
80 */
81 public function cli_getArgArray($option, $argv)
82 {
83 while (count($argv) && (string)$argv[0] !== (string)$option) {
84 array_shift($argv);
85 }
86 if ((string)$argv[0] === (string)$option) {
87 array_shift($argv);
88 return !empty($argv) ? $argv : [''];
89 }
90 }
91
92 /**
93 * Return TRUE if option is found
94 *
95 * @param string $option Option string, eg. "-s
96 * @return bool TRUE if option found
97 */
98 public function cli_isArg($option)
99 {
100 return isset($this->cli_args[$option]);
101 }
102
103 /**
104 * Return argument value
105 *
106 * @param string $option Option string, eg. "-s
107 * @param int $idx Value index, default is 0 (zero) = the first one...
108 * @return bool TRUE if option found
109 */
110 public function cli_argValue($option, $idx = 0)
111 {
112 return is_array($this->cli_args[$option]) ? $this->cli_args[$option][$idx] : '';
113 }
114
115 /**
116 * Will parse "_SERVER[argv]" into an index of options and values
117 * Argument names (eg. "-s") will be keys and values after (eg. "-s value1 value2 ..." or "-s=value1") will be in the array.
118 * Array is empty if no values
119 *
120 * @param array $argv Configuration options
121 * @return array
122 */
123 public function cli_getArgIndex(array $argv = [])
124 {
125 $cli_options = [];
126 $index = '_DEFAULT';
127 foreach ($argv as $token) {
128 // Options starting with a number is invalid - they could be negative values!
129 if ($token[0] === '-' && !\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($token[1])) {
130 list($index, $opt) = explode('=', $token, 2);
131 if (isset($cli_options[$index])) {
132 echo 'ERROR: Option ' . $index . ' was used twice!' . LF;
133 die;
134 }
135 $cli_options[$index] = [];
136 if (isset($opt)) {
137 $cli_options[$index][] = $opt;
138 }
139 } else {
140 $cli_options[$index][] = $token;
141 }
142 }
143 return $cli_options;
144 }
145
146 /**
147 * Validates if the input arguments in this->cli_args are all listed in this->cli_options and if not,
148 * will exit with an error.
149 *
150 */
151 public function cli_validateArgs()
152 {
153 $cli_args_copy = $this->cli_args;
154 unset($cli_args_copy['_DEFAULT']);
155 $allOptions = [];
156 foreach ($this->cli_options as $cfg) {
157 $allOptions[] = $cfg[0];
158 $argSplit = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(' ', $cfg[0], true);
159 if (isset($cli_args_copy[$argSplit[0]])) {
160 $ii = 0;
161 foreach ($argSplit as $i => $v) {
162 $ii = $i;
163 if ($i > 0) {
164 if (!isset($cli_args_copy[$argSplit[0]][$i - 1]) && $v[0] !== '[') {
165 // Using "[]" around a parameter makes it optional
166 echo 'ERROR: Option "' . $argSplit[0] . '" requires a value ("' . $v . '") on position ' . $i . LF;
167 die;
168 }
169 }
170 }
171 $ii++;
172 if (isset($cli_args_copy[$argSplit[0]][$ii - 1])) {
173 echo 'ERROR: Option "' . $argSplit[0] . '" does not support a value on position ' . $ii . LF;
174 die;
175 }
176 unset($cli_args_copy[$argSplit[0]]);
177 }
178 }
179 if (!empty($cli_args_copy)) {
180 echo wordwrap('ERROR: Option ' . implode(',', array_keys($cli_args_copy)) . ' was unknown to this script!' . LF . '(Options are: ' . implode(', ', $allOptions) . ')' . LF);
181 die;
182 }
183 }
184
185 /**
186 * Set environment array to $cli_args
187 *
188 * @param array $argv Configuration options
189 * @return void
190 */
191 public function cli_setArguments(array $argv = [])
192 {
193 $this->cli_args = $this->cli_getArgIndex($argv);
194 }
195
196 /**
197 * Asks stdin for keyboard input and returns the line (after enter is pressed)
198 *
199 * @return string
200 */
201 public function cli_keyboardInput()
202 {
203 // Have to open the stdin stream only ONCE! otherwise I cannot read multiple lines from it... :
204 if (!$this->stdin) {
205 $this->stdin = fopen('php://stdin', 'r');
206 }
207 while (false == ($line = fgets($this->stdin, 1000))) {
208 }
209 return trim($line);
210 }
211
212 /**
213 * Asks for Yes/No from shell and returns TRUE if "y" or "yes" is found as input.
214 *
215 * @param string $msg String to ask before...
216 * @return bool TRUE if "y" or "yes" is the input (case insensitive)
217 */
218 public function cli_keyboardInput_yes($msg = '')
219 {
220 // ONLY makes sense to echo it out since we are awaiting keyboard input - that cannot be silenced
221 echo $msg . ' (Yes/No + return): ';
222 $input = strtolower($this->cli_keyboardInput());
223 return $input === 'y' || $input === 'yes';
224 }
225
226 /**
227 * Echos strings to shell, but respective silent-modes
228 *
229 * @param string $string The string
230 * @param bool $force If string should be written even if -s is set (-ss will subdue it!)
231 * @return bool Returns TRUE if string was outputted.
232 */
233 public function cli_echo($string = '', $force = false)
234 {
235 if (isset($this->cli_args['-ss'])) {
236 } elseif (isset($this->cli_args['-s']) || isset($this->cli_args['--silent'])) {
237 if ($force) {
238 echo $string;
239 return true;
240 }
241 } else {
242 echo $string;
243 return true;
244 }
245 return false;
246 }
247
248 /**
249 * Prints help-output from ->cli_help array
250 *
251 * @return void
252 */
253 public function cli_help()
254 {
255 foreach ($this->cli_help as $key => $value) {
256 $this->cli_echo(strtoupper($key) . ':
257 ');
258 switch ($key) {
259 case 'synopsis':
260 $optStr = '';
261 foreach ($this->cli_options as $v) {
262 $optStr .= ' [' . $v[0] . ']';
263 }
264 $this->cli_echo($this->cli_indent(str_replace('###OPTIONS###', trim($optStr), $value), 4) . '
265
266 ');
267 break;
268 case 'options':
269 $this->cli_echo($this->cli_indent($value, 4) . LF);
270 $maxLen = 0;
271 foreach ($this->cli_options as $v) {
272 if (strlen($v[0]) > $maxLen) {
273 $maxLen = strlen($v[0]);
274 }
275 }
276 foreach ($this->cli_options as $v) {
277 $this->cli_echo($v[0] . substr($this->cli_indent(rtrim($v[1] . LF . $v[2]), $maxLen + 4), strlen($v[0])) . LF);
278 }
279 $this->cli_echo(LF);
280 break;
281 default:
282 $this->cli_echo($this->cli_indent($value, 4) . '
283
284 ');
285 }
286 }
287 }
288
289 /**
290 * Indentation function for 75 char wide lines.
291 *
292 * @param string $str String to break and indent.
293 * @param int $indent Number of space chars to indent.
294 * @return string Result
295 */
296 public function cli_indent($str, $indent)
297 {
298 $lines = explode(LF, wordwrap($str, 75 - $indent));
299 $indentStr = str_pad('', $indent, ' ');
300 foreach ($lines as $k => $v) {
301 $lines[$k] = $indentStr . $lines[$k];
302 }
303 return implode(LF, $lines);
304 }
305 }