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