[BUGFIX] Merge t3lib_exec class with t3lib_utility_Command
authorTymoteusz Motylewski <t.motylewski@gmail.com>
Fri, 24 Aug 2012 21:08:07 +0000 (23:08 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Fri, 24 Aug 2012 21:35:50 +0000 (23:35 +0200)
After namespace change both classes t3lib_utility_Command t3lib_exec
are mapped to the new class TYPO3\CMS\Core\Utility\CommandUtility

This patch adds missing t3lib_exec content to CommandUtility.

Mapping old classes names to new one is already done for both classes.

Related: #40095
Fixes: #40146
Release: 6.0

Change-Id: Iaed788ddebd42ed115c986fc7d6d056f73d29cb9
Reviewed-on: http://review.typo3.org/14056
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
typo3/sysext/core/Classes/Utility/CommandUtility.php

index 7aace97..9f4dc49 100644 (file)
@@ -28,12 +28,63 @@ namespace TYPO3\CMS\Core\Utility;
  ***************************************************************/
 /**
  * Class to handle system commands.
+ * finds executables (programs) on Unix and Windows without knowing where they are
+ *
+ * returns exec command for a program
+ * or FALSE
+ *
+ * This class is meant to be used without instance:
+ * $cmd = CommandUtility::getCommand ('awstats','perl');
+ *
+ * The data of this class is cached.
+ * That means if a program is found once it don't have to be searched again.
+ *
+ * user functions:
+ *
+ * addPaths() could be used to extend the search paths
+ * getCommand() get a command string
+ * checkCommand() returns TRUE if a command is available
+ *
+ * Search paths that are included:
+ * $TYPO3_CONF_VARS['GFX']['im_path_lzw'] or $TYPO3_CONF_VARS['GFX']['im_path']
+ * $TYPO3_CONF_VARS['SYS']['binPath']
+ * $GLOBALS['_SERVER']['PATH']
+ * '/usr/bin/,/usr/local/bin/' on Unix
+ *
+ * binaries can be preconfigured with
+ * $TYPO3_CONF_VARS['SYS']['binSetup']
  *
  * @author Steffen Kamper <steffen@typo3.org>
+ * @author RenĂ© Fritz <r.fritz@colorcube.de>
  */
 final class CommandUtility {
 
        /**
+        * Tells if object is already initialized
+        *
+        * @var boolean
+        */
+       protected static $initialized = FALSE;
+
+       /**
+        * Contains application list. This is an array with the following structure:
+        * - app => file name to the application (like 'tar' or 'bzip2')
+        * - path => full path to the application without application name (like '/usr/bin/' for '/usr/bin/tar')
+        * - valid => TRUE or FALSE
+        * Array key is identical to 'app'.
+        *
+        * @var array
+        */
+       protected static $applications = array();
+
+       /**
+        * Paths where to search for applications
+        *
+        * @var array
+        */
+       protected static $paths = NULL;
+
+       /**
         * Wrapper function for php exec function
         * Needs to be central to have better control and possible fix for issues
         *
@@ -107,6 +158,284 @@ final class CommandUtility {
                return $cmdLine;
        }
 
+       /**
+        * Checks if a command is valid or not, updates global variables
+        *
+        * @param string $cmd The command that should be executed. eg: "convert"
+        * @param string $handler Executer for the command. eg: "perl"
+        * @return boolean FALSE if cmd is not found, or -1 if the handler is not found
+        */
+       public static function checkCommand($cmd, $handler = '') {
+               if (!self::init()) {
+                       return FALSE;
+               }
+
+               if ($handler && !self::checkCommand($handler)) {
+                       return -1;
+               }
+                       // Already checked and valid
+               if (self::$applications[$cmd]['valid']) {
+                       return TRUE;
+               }
+                       // Is set but was (above) not TRUE
+               if (isset(self::$applications[$cmd]['valid'])) {
+                       return FALSE;
+               }
+
+               foreach (self::$paths as $path => $validPath) {
+                               // Ignore invalid (FALSE) paths
+                       if ($validPath) {
+                               if (TYPO3_OS == 'WIN') {
+                                               // Windows OS
+                                               // TODO Why is_executable() is not called here?
+                                       if (@is_file($path . $cmd)) {
+                                               self::$applications[$cmd]['app'] = $cmd;
+                                               self::$applications[$cmd]['path'] = $path;
+                                               self::$applications[$cmd]['valid'] = TRUE;
+                                               return TRUE;
+                                       }
+                                       if (@is_file($path . $cmd . '.exe')) {
+                                               self::$applications[$cmd]['app'] = $cmd . '.exe';
+                                               self::$applications[$cmd]['path'] = $path;
+                                               self::$applications[$cmd]['valid'] = TRUE;
+                                               return TRUE;
+                                       }
+                               } else {
+                                               // Unix-like OS
+                                       $filePath = realpath($path . $cmd);
+                                       if ($filePath && @is_executable($filePath)) {
+                                               self::$applications[$cmd]['app'] = $cmd;
+                                               self::$applications[$cmd]['path'] = $path;
+                                               self::$applications[$cmd]['valid'] = TRUE;
+                                               return TRUE;
+                                       }
+                               }
+                       }
+               }
+
+                       // Try to get the executable with the command 'which'.
+                       // It does the same like already done, but maybe on other paths
+               if (TYPO3_OS != 'WIN') {
+                       $cmd = @self::exec('which ' . $cmd);
+                       if (@is_executable($cmd)) {
+                               self::$applications[$cmd]['app'] = $cmd;
+                               self::$applications[$cmd]['path'] = dirname($cmd) . '/';
+                               self::$applications[$cmd]['valid'] = TRUE;
+                               return TRUE;
+                       }
+               }
+
+               return FALSE;
+       }
+
+       /**
+        * Returns a command string for exec(), system()
+        *
+        * @param string $cmd The command that should be executed. eg: "convert"
+        * @param string $handler Handler (executor) for the command. eg: "perl"
+        * @param string $handlerOpt Options for the handler, like '-w' for "perl"
+        * @return mixed Returns command string, or FALSE if cmd is not found, or -1 if the handler is not found
+        */
+       public static function getCommand($cmd, $handler = '', $handlerOpt = '') {
+               if (!self::init()) {
+                       return FALSE;
+               }
+
+                       // Handler
+               if ($handler) {
+                       $handler = self::getCommand($handler);
+
+                       if (!$handler) {
+                               return -1;
+                       }
+                       $handler .= ' ' . $handlerOpt . ' ';
+               }
+
+                       // Command
+               if (!self::checkCommand($cmd)) {
+                       return FALSE;
+               }
+               $cmd = self::$applications[$cmd]['path'] . self::$applications[$cmd]['app'] . ' ';
+
+               return trim($handler . $cmd);
+       }
+
+       /**
+        * Extend the preset paths. This way an extension can install an executable and provide the path to t3lib_exec.
+        *
+        * @param string $paths Comma separated list of extra paths where a command should be searched. Relative paths (without leading "/") are prepend with site root path (PATH_site).
+        * @return void
+        */
+       public static function addPaths($paths) {
+               self::initPaths($paths);
+       }
+
+       /**
+        * Returns an array of search paths
+        *
+        * @param boolean $addInvalid If set the array contains invalid path too. Then the key is the path and the value is empty
+        * @return array Array of search paths (empty if exec is disabled)
+        */
+       public static function getPaths($addInvalid = FALSE) {
+               if (!self::init()) {
+                       return array();
+               }
+
+               $paths = self::$paths;
+
+               if (!$addInvalid) {
+                       foreach ($paths as $path => $validPath) {
+                               if (!$validPath) {
+                                       unset($paths[$path]);
+                               }
+                       }
+               }
+               return $paths;
+       }
+
+       /**
+        * Initializes this class
+        *
+        * @return boolean
+        */
+       protected static function init() {
+               if ($GLOBALS['TYPO3_CONF_VARS']['BE']['disable_exec_function']) {
+                       return FALSE;
+               }
+               if (!self::$initialized) {
+                       self::initPaths();
+                       self::$applications = self::getConfiguredApps();
+                       self::$initialized = TRUE;
+               }
+               return TRUE;
+       }
+
+       /**
+        * Initializes and extends the preset paths with own
+        *
+        * @param string $paths Comma separated list of extra paths where a command should be searched. Relative paths (without leading "/") are prepend with site root path (PATH_site).
+        * @return void
+        */
+       protected static function initPaths($paths = '') {
+               $doCheck = FALSE;
+
+                       // Init global paths array if not already done
+               if (!is_array(self::$paths)) {
+                       self::$paths = self::getPathsInternal();
+                       $doCheck = TRUE;
+               }
+                       // Merge the submitted paths array to the global
+               if ($paths) {
+                       $paths = GeneralUtility::trimExplode(',', $paths, 1);
+                       if (is_array($paths)) {
+                               foreach ($paths as $path) {
+                                               // Make absolute path of relative
+                                       if (!preg_match('#^/#', $path)) {
+                                               $path = PATH_site . $path;
+                                       }
+                                       if (!isset(self::$paths[$path])) {
+                                               if (@is_dir($path)) {
+                                                       self::$paths[$path] = $path;
+                                               } else {
+                                                       self::$paths[$path] = FALSE;
+                                               }
+                                       }
+                               }
+                       }
+               }
+                       // Check if new paths are invalid
+               if ($doCheck) {
+                       foreach (self::$paths as $path => $valid) {
+                                       // Ignore invalid (FALSE) paths
+                               if ($valid AND !@is_dir($path)) {
+                                       self::$paths[$path] = FALSE;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Processes and returns the paths from $GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']
+        *
+        * @return array Array of commands and path
+        */
+       protected static function getConfiguredApps() {
+               $cmdArr = array();
+
+               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']) {
+                       $pathSetup = preg_split('/[\n,]+/', $GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']);
+                       foreach ($pathSetup as $val) {
+                               list($cmd, $cmdPath) = GeneralUtility::trimExplode('=', $val, 1);
+                               $cmdArr[$cmd]['app'] = basename($cmdPath);
+                               $cmdArr[$cmd]['path'] = dirname($cmdPath) . '/';
+                               $cmdArr[$cmd]['valid'] = TRUE;
+                       }
+               }
+
+               return $cmdArr;
+       }
+
+       /**
+        * Sets the search paths from different sources, internal
+        *
+        * @return array Array of absolute paths (keys and values are equal)
+        */
+       protected static function getPathsInternal() {
+
+               $pathsArr = array();
+               $sysPathArr = array();
+
+                       // Image magick paths first
+                       // im_path_lzw take precedence over im_path
+               if (($imPath = ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw'] ? $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw'] : $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path']))) {
+                       $imPath = self::fixPath($imPath);
+                       $pathsArr[$imPath] = $imPath;
+               }
+
+                       // Add configured paths
+               if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath']) {
+                       $sysPath = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath'], 1);
+                       foreach ($sysPath as $val) {
+                               $val = self::fixPath($val);
+                               $sysPathArr[$val] = $val;
+                       }
+               }
+
+                       // Add path from environment
+                       // TODO: how does this work for WIN
+               if ($GLOBALS['_SERVER']['PATH']) {
+                       $sep = (TYPO3_OS == 'WIN' ? ';' : ':');
+                       $envPath = GeneralUtility::trimExplode($sep, $GLOBALS['_SERVER']['PATH'], 1);
+                       foreach ($envPath as $val) {
+                               $val = self::fixPath($val);
+                               $sysPathArr[$val] = $val;
+                       }
+               }
+
+                       // Set common paths for Unix (only)
+               if (TYPO3_OS !== 'WIN') {
+                       $sysPathArr = array_merge($sysPathArr, array(
+                               '/usr/bin/' => '/usr/bin/',
+                               '/usr/local/bin/' => '/usr/local/bin/',
+                       ));
+               }
+
+               $pathsArr = array_merge($pathsArr, $sysPathArr);
+
+               return $pathsArr;
+       }
+
+
+       /**
+        * Set a path to the right format
+        *
+        * @param string $path Input path
+        * @return string Output path
+        */
+       protected static function fixPath($path) {
+               return str_replace('//', '/', $path . '/');
+       }
+
 }