TYPO3 API  SVNRelease
class.t3lib_cli.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 2006-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
00006  *  All rights reserved
00007  *
00008  *  This script is part of the TYPO3 project. The TYPO3 project is
00009  *  free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  The GNU General Public License can be found at
00015  *  http://www.gnu.org/copyleft/gpl.html.
00016  *  A copy is found in the textfile GPL.txt and important notices to the license
00017  *  from the author is found in LICENSE.txt distributed with these scripts.
00018  *
00019  *
00020  *  This script is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  This copyright notice MUST APPEAR in all copies of the script!
00026  ***************************************************************/
00027 /**
00028  * Contains base class for TYPO3 cli scripts
00029  *
00030  * $Id: class.t3lib_cli.php 10121 2011-01-18 20:15:30Z ohader $
00031  *
00032  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00033  */
00034 /**
00035  * [CLASS/FUNCTION INDEX of SCRIPT]
00036  *
00037  *
00038  *
00039  *   60: class t3lib_cli
00040  *   83:     function t3lib_cli()
00041  *   96:     function cli_getArg($option,$argv)
00042  *  112:     function cli_getArgIndex()
00043  *  131:     function cli_keyboardInput()
00044  *  142:     function cli_keyboardInput_yes()
00045  *  154:     function cli_echo($string='',$force=FALSE)
00046  *  169:     function cli_help()
00047  *  207:     function cli_indent($str,$indent)
00048  *
00049  * TOTAL FUNCTIONS: 8
00050  * (This index is automatically created/updated by the extension "extdeveval")
00051  *
00052  */
00053 
00054 
00055 /**
00056  * TYPO3 cli script basis
00057  *
00058  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00059  * @package TYPO3
00060  * @subpackage t3lib
00061  */
00062 class t3lib_cli {
00063 
00064     var $cli_args = array(); // Command line arguments, exploded into key => value-array pairs
00065     var $cli_options = array(
00066         array('-s', 'Silent operation, will only output errors and important messages.'),
00067         array('--silent', 'Same as -s'),
00068         array('-ss', 'Super silent, will not even output errors or important messages.'),
00069     );
00070     var $cli_help = array(
00071         'name' => 'CLI base class (overwrite this...)',
00072         'synopsis' => '###OPTIONS###',
00073         'description' => 'Class with basic functionality for CLI scripts (overwrite this...)',
00074         'examples' => 'Give examples...',
00075         'options' => '',
00076         'license' => 'GNU GPL - free software!',
00077         'author' => '[Author name]',
00078     );
00079     var $stdin = NULL;
00080 
00081 
00082     /**
00083      * Constructor
00084      * Make sure child classes also call this!
00085      *
00086      * @return  void
00087      */
00088     function t3lib_cli() {
00089             // Loads the cli_args array with command line arguments
00090         $this->cli_args = $this->cli_getArgIndex();
00091     }
00092 
00093     /**
00094      * Finds the arg token (like "-s") in argv and returns the rest of argv from that point on.
00095      * This should only be used in special cases since this->cli_args should already be prepared with an index of values!
00096      *
00097      * @param   string      Option string, eg. "-s"
00098      * @param   array       Input argv array
00099      * @return  array       Output argv array with all options AFTER the found option.
00100      */
00101     function cli_getArgArray($option, $argv) {
00102         while (count($argv) && strcmp($argv[0], $option)) {
00103             array_shift($argv);
00104         }
00105 
00106         if (!strcmp($argv[0], $option)) {
00107             array_shift($argv);
00108             return count($argv) ? $argv : array('');
00109         }
00110     }
00111 
00112     /**
00113      * Return true if option is found
00114      *
00115      * @param   string      Option string, eg. "-s"
00116      * @return  boolean     TRUE if option found
00117      */
00118     function cli_isArg($option) {
00119         return isset($this->cli_args[$option]);
00120     }
00121 
00122     /**
00123      * Return argument value
00124      *
00125      * @param   string      Option string, eg. "-s"
00126      * @param   integer     Value index, default is 0 (zero) = the first one...
00127      * @return  boolean     TRUE if option found
00128      */
00129     function cli_argValue($option, $idx = 0) {
00130         return is_array($this->cli_args[$option]) ? $this->cli_args[$option][$idx] : '';
00131     }
00132 
00133     /**
00134      * Will parse "_SERVER[argv]" into an index of options and values
00135      * Argument names (eg. "-s") will be keys and values after (eg. "-s value1 value2 ..." or "-s=value1") will be in the array.
00136      * Array is empty if no values
00137      *
00138      * @return  array
00139      */
00140     function cli_getArgIndex() {
00141         $cli_options = array();
00142         $index = '_DEFAULT';
00143         foreach ($_SERVER['argv'] as $token) {
00144             if ($token{0} === '-' && !t3lib_div::testInt($token{1})) { // Options starting with a number is invalid - they could be negative values... !
00145                 list($index, $opt) = explode('=', $token, 2);
00146                 if (isset($cli_options[$index])) {
00147                     echo 'ERROR: Option ' . $index . ' was used twice!' . LF;
00148                     exit;
00149                 }
00150                 $cli_options[$index] = array();
00151                 if (isset($opt)) {
00152                     $cli_options[$index][] = $opt;
00153                 }
00154             } else {
00155                 $cli_options[$index][] = $token;
00156             }
00157         }
00158 
00159         return $cli_options;
00160     }
00161 
00162     /**
00163      * Validates if the input arguments in this->cli_args are all listed in this->cli_options and if not, will exit with an error.
00164      */
00165     function cli_validateArgs() {
00166         $cli_args_copy = $this->cli_args;
00167         unset($cli_args_copy['_DEFAULT']);
00168         $allOptions = array();
00169 
00170         foreach ($this->cli_options as $cfg) {
00171             $allOptions[] = $cfg[0];
00172             $argSplit = t3lib_div::trimExplode(' ', $cfg[0], 1);
00173             if (isset($cli_args_copy[$argSplit[0]])) {
00174 
00175                 foreach ($argSplit as $i => $v) {
00176                     $ii = $i;
00177                     if ($i > 0) {
00178                         if (!isset($cli_args_copy[$argSplit[0]][$i - 1]) && $v{0} != '[') { // Using "[]" around a paramter makes it optional
00179                             echo 'ERROR: Option "' . $argSplit[0] . '" requires a value ("' . $v . '") on position ' . $i . LF;
00180                             exit;
00181                         }
00182                     }
00183                 }
00184 
00185                 $ii++;
00186                 if (isset($cli_args_copy[$argSplit[0]][$ii - 1])) {
00187                     echo 'ERROR: Option "' . $argSplit[0] . '" does not support a value on position ' . $ii . LF;
00188                     exit;
00189                 }
00190 
00191                 unset($cli_args_copy[$argSplit[0]]);
00192             }
00193         }
00194 
00195         if (count($cli_args_copy)) {
00196             echo wordwrap('ERROR: Option ' . implode(',', array_keys($cli_args_copy)) . ' was unknown to this script!' . LF . '(Options are: ' . implode(', ', $allOptions) . ')' . LF);
00197             exit;
00198         }
00199     }
00200 
00201     /**
00202      * Asks stdin for keyboard input and returns the line (after enter is pressed)
00203      *
00204      * @return  string
00205      */
00206     function cli_keyboardInput() {
00207 
00208             // Have to open the stdin stream only ONCE! otherwise I cannot read multiple lines from it... :
00209         if (!$this->stdin) {
00210             $this->stdin = fopen('php://stdin', 'r');
00211         }
00212 
00213         while (FALSE == ($line = fgets($this->stdin, 1000))) {
00214         }
00215 
00216         return trim($line);
00217     }
00218 
00219     /**
00220      * Asks for Yes/No from shell and returns true if "y" or "yes" is found as input.
00221      *
00222      * @param   string      String to ask before...
00223      * @return  boolean     TRUE if "y" or "yes" is the input (case insensitive)
00224      */
00225     function cli_keyboardInput_yes($msg = '') {
00226         echo $msg . ' (Yes/No + return): '; // ONLY makes sense to echo it out since we are awaiting keyboard input - that cannot be silenced...
00227 
00228         return t3lib_div::inList('y,yes', strtolower($this->cli_keyboardInput()));
00229     }
00230 
00231     /**
00232      * Echos strings to shell, but respective silent-modes
00233      *
00234      * @param   string      The string
00235      * @param   boolean     If string should be written even if -s is set (-ss will subdue it!)
00236      * @return  boolean     Returns TRUE if string was outputted.
00237      */
00238     function cli_echo($string = '', $force = FALSE) {
00239         if (isset($this->cli_args['-ss'])) {
00240             // Nothing to do...
00241         } elseif (isset($this->cli_args['-s']) || isset($this->cli_args['--silent'])) {
00242             if ($force) {
00243                 echo $string;
00244                 return TRUE;
00245             }
00246         } else {
00247             echo $string;
00248             return TRUE;
00249         }
00250 
00251         return FALSE;
00252     }
00253 
00254     /**
00255      * Prints help-output from ->cli_help array
00256      *
00257      * @return  void
00258      */
00259     function cli_help() {
00260         foreach ($this->cli_help as $key => $value) {
00261             $this->cli_echo(strtoupper($key) . ":\n");
00262             switch ($key) {
00263                 case 'synopsis':
00264                     $optStr = '';
00265                     foreach ($this->cli_options as $v) {
00266                         $optStr .= ' [' . $v[0] . ']';
00267                     }
00268                     $this->cli_echo($this->cli_indent(str_replace('###OPTIONS###', trim($optStr), $value), 4) . "\n\n");
00269                     break;
00270                 case 'options':
00271                     $this->cli_echo($this->cli_indent($value, 4) . LF);
00272 
00273                     $maxLen = 0;
00274                     foreach ($this->cli_options as $v) {
00275                         if (strlen($v[0]) > $maxLen) {
00276                             $maxLen = strlen($v[0]);
00277                         }
00278                     }
00279 
00280                     foreach ($this->cli_options as $v) {
00281                         $this->cli_echo($v[0] . substr($this->cli_indent(rtrim($v[1] . LF . $v[2]), $maxLen + 4), strlen($v[0])) . LF);
00282                     }
00283                     $this->cli_echo(LF);
00284                     break;
00285                 default:
00286                     $this->cli_echo($this->cli_indent($value, 4) . "\n\n");
00287                     break;
00288             }
00289         }
00290     }
00291 
00292     /**
00293      * Indentation function for 75 char wide lines.
00294      *
00295      * @param   string      String to break and indent.
00296      * @param   integer     Number of space chars to indent.
00297      * @return  string      Result
00298      */
00299     function cli_indent($str, $indent) {
00300         $lines = explode(LF, wordwrap($str, 75 - $indent));
00301         $indentStr = str_pad('', $indent, ' ');
00302         foreach ($lines as $k => $v) {
00303             $lines[$k] = $indentStr . $lines[$k];
00304         }
00305 
00306         return implode(LF, $lines);
00307     }
00308 }
00309 
00310 ?>