TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
CommandUtility.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Utility;
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 
46 {
52  protected static $initialized = false;
53 
63  protected static $applications = [];
64 
70  protected static $paths = null;
71 
81  public static function exec($command, &$output = null, &$returnValue = 0)
82  {
83  return exec($command, $output, $returnValue);
84  }
85 
94  public static function imageMagickCommand($command, $parameters, $path = '')
95  {
96  $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
97  $isExt = TYPO3_OS === 'WIN' ? '.exe' : '';
98  if (!$path) {
99  $path = $gfxConf['processor_path'];
100  }
101  $path = GeneralUtility::fixWindowsFilePath($path);
102  // This is only used internally, has no effect outside
103  if ($command === 'combine') {
104  $command = 'composite';
105  }
106  // Compile the path & command
107  if ($gfxConf['processor'] === 'GraphicsMagick') {
108  $path = self::escapeShellArgument($path . 'gm' . $isExt) . ' ' . self::escapeShellArgument($command);
109  } else {
110  $path = self::escapeShellArgument($path . $command . $isExt);
111  }
112  // strip profile information for thumbnails and reduce their size
113  if ($parameters && $command !== 'identify'
114  && $gfxConf['processor_stripColorProfileByDefault']
115  && $gfxConf['processor_stripColorProfileCommand'] !== ''
116  && strpos($parameters, $gfxConf['processor_stripColorProfileCommand']) === false
117  ) {
118  // Determine whether the strip profile action has be disabled by TypoScript:
119  if ($parameters !== '-version' && strpos($parameters, '###SkipStripProfile###') === false) {
120  $parameters = $gfxConf['processor_stripColorProfileCommand'] . ' ' . $parameters;
121  } else {
122  $parameters = str_replace('###SkipStripProfile###', '', $parameters);
123  }
124  }
125  $cmdLine = $path . ' ' . $parameters;
126  // It is needed to change the parameters order when a mask image has been specified
127  if ($command === 'composite') {
128  $paramsArr = GeneralUtility::unQuoteFilenames($parameters);
129  $paramsArrCount = count($paramsArr);
130  if ($paramsArrCount > 5) {
131  $tmp = $paramsArr[$paramsArrCount - 3];
132  $paramsArr[$paramsArrCount - 3] = $paramsArr[$paramsArrCount - 4];
133  $paramsArr[$paramsArrCount - 4] = $tmp;
134  }
135  $cmdLine = $path . ' ' . implode(' ', $paramsArr);
136  }
137  return $cmdLine;
138  }
139 
147  public static function checkCommand($cmd, $handler = '')
148  {
149  if (!self::init()) {
150  return false;
151  }
152 
153  if ($handler && !self::checkCommand($handler)) {
154  return -1;
155  }
156  // Already checked and valid
157  if (self::$applications[$cmd]['valid']) {
158  return true;
159  }
160  // Is set but was (above) not TRUE
161  if (isset(self::$applications[$cmd]['valid'])) {
162  return false;
163  }
164 
165  foreach (self::$paths as $path => $validPath) {
166  // Ignore invalid (FALSE) paths
167  if ($validPath) {
168  if (TYPO3_OS === 'WIN') {
169  // Windows OS
170  // @todo Why is_executable() is not called here?
171  if (@is_file($path . $cmd)) {
172  self::$applications[$cmd]['app'] = $cmd;
173  self::$applications[$cmd]['path'] = $path;
174  self::$applications[$cmd]['valid'] = true;
175  return true;
176  }
177  if (@is_file($path . $cmd . '.exe')) {
178  self::$applications[$cmd]['app'] = $cmd . '.exe';
179  self::$applications[$cmd]['path'] = $path;
180  self::$applications[$cmd]['valid'] = true;
181  return true;
182  }
183  } else {
184  // Unix-like OS
185  $filePath = realpath($path . $cmd);
186  if ($filePath && @is_executable($filePath)) {
187  self::$applications[$cmd]['app'] = $cmd;
188  self::$applications[$cmd]['path'] = $path;
189  self::$applications[$cmd]['valid'] = true;
190  return true;
191  }
192  }
193  }
194  }
195 
196  // Try to get the executable with the command 'which'.
197  // It does the same like already done, but maybe on other paths
198  if (TYPO3_OS !== 'WIN') {
199  $cmd = @self::exec('which ' . $cmd);
200  if (@is_executable($cmd)) {
201  self::$applications[$cmd]['app'] = $cmd;
202  self::$applications[$cmd]['path'] = dirname($cmd) . '/';
203  self::$applications[$cmd]['valid'] = true;
204  return true;
205  }
206  }
207 
208  return false;
209  }
210 
219  public static function getCommand($cmd, $handler = '', $handlerOpt = '')
220  {
221  if (!self::init()) {
222  return false;
223  }
224 
225  // Handler
226  if ($handler) {
227  $handler = self::getCommand($handler);
228 
229  if (!$handler) {
230  return -1;
231  }
232  $handler .= ' ' . $handlerOpt . ' ';
233  }
234 
235  // Command
236  if (!self::checkCommand($cmd)) {
237  return false;
238  }
239  $cmd = self::$applications[$cmd]['path'] . self::$applications[$cmd]['app'] . ' ';
240 
241  return trim($handler . $cmd);
242  }
243 
250  public static function addPaths($paths)
251  {
252  self::initPaths($paths);
253  }
254 
261  public static function getPaths($addInvalid = false)
262  {
263  if (!self::init()) {
264  return [];
265  }
266 
267  $paths = self::$paths;
268 
269  if (!$addInvalid) {
270  foreach ($paths as $path => $validPath) {
271  if (!$validPath) {
272  unset($paths[$path]);
273  }
274  }
275  }
276  return $paths;
277  }
278 
284  protected static function init()
285  {
286  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['disable_exec_function']) {
287  return false;
288  }
289  if (!self::$initialized) {
290  self::initPaths();
291  self::$applications = self::getConfiguredApps();
292  self::$initialized = true;
293  }
294  return true;
295  }
296 
303  protected static function initPaths($paths = '')
304  {
305  $doCheck = false;
306 
307  // Init global paths array if not already done
308  if (!is_array(self::$paths)) {
309  self::$paths = self::getPathsInternal();
310  $doCheck = true;
311  }
312  // Merge the submitted paths array to the global
313  if ($paths) {
315  if (is_array($paths)) {
316  foreach ($paths as $path) {
317  // Make absolute path of relative
318  if (!preg_match('#^/#', $path)) {
319  $path = PATH_site . $path;
320  }
321  if (!isset(self::$paths[$path])) {
322  if (@is_dir($path)) {
323  self::$paths[$path] = $path;
324  } else {
325  self::$paths[$path] = false;
326  }
327  }
328  }
329  }
330  }
331  // Check if new paths are invalid
332  if ($doCheck) {
333  foreach (self::$paths as $path => $valid) {
334  // Ignore invalid (FALSE) paths
335  if ($valid && !@is_dir($path)) {
336  self::$paths[$path] = false;
337  }
338  }
339  }
340  }
341 
347  protected static function getConfiguredApps()
348  {
349  $cmdArr = [];
350 
351  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']) {
352  $binSetup = str_replace(['\'.chr(10).\'', '\' . LF . \''], LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']);
353  $pathSetup = preg_split('/[\n,]+/', $binSetup);
354  foreach ($pathSetup as $val) {
355  if (trim($val) === '') {
356  continue;
357  }
358  list($cmd, $cmdPath) = GeneralUtility::trimExplode('=', $val, true, 2);
359  $cmdArr[$cmd]['app'] = basename($cmdPath);
360  $cmdArr[$cmd]['path'] = dirname($cmdPath) . '/';
361  $cmdArr[$cmd]['valid'] = true;
362  }
363  }
364 
365  return $cmdArr;
366  }
367 
373  protected static function getPathsInternal()
374  {
375  $pathsArr = [];
376  $sysPathArr = [];
377 
378  // Image magick paths first
379  // processor_path_lzw take precedence over processor_path
380  if ($imPath = $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path_lzw'] ?: $GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path']) {
381  $imPath = self::fixPath($imPath);
382  $pathsArr[$imPath] = $imPath;
383  }
384 
385  // Add configured paths
386  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath']) {
387  $sysPath = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath'], true);
388  foreach ($sysPath as $val) {
389  $val = self::fixPath($val);
390  $sysPathArr[$val] = $val;
391  }
392  }
393 
394  // Add path from environment
395  // @todo how does this work for WIN
396  if ($GLOBALS['_SERVER']['PATH']) {
397  $sep = (TYPO3_OS === 'WIN' ? ';' : ':');
398  $envPath = GeneralUtility::trimExplode($sep, $GLOBALS['_SERVER']['PATH'], true);
399  foreach ($envPath as $val) {
400  $val = self::fixPath($val);
401  $sysPathArr[$val] = $val;
402  }
403  }
404 
405  // Set common paths for Unix (only)
406  if (TYPO3_OS !== 'WIN') {
407  $sysPathArr = array_merge($sysPathArr, [
408  '/usr/bin/' => '/usr/bin/',
409  '/usr/local/bin/' => '/usr/local/bin/',
410  ]);
411  }
412 
413  $pathsArr = array_merge($pathsArr, $sysPathArr);
414 
415  return $pathsArr;
416  }
417 
424  protected static function fixPath($path)
425  {
426  return str_replace('//', '/', $path . '/');
427  }
428 
437  public static function escapeShellArguments(array $input)
438  {
439  $isUTF8Filesystem = !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']);
440  if ($isUTF8Filesystem) {
441  $currentLocale = setlocale(LC_CTYPE, 0);
442  setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
443  }
444 
445  $output = array_map('escapeshellarg', $input);
446 
447  if ($isUTF8Filesystem) {
448  setlocale(LC_CTYPE, $currentLocale);
449  }
450 
451  return $output;
452  }
453 
462  public static function escapeShellArgument($input)
463  {
464  return self::escapeShellArguments([$input])[0];
465  }
466 }
static checkCommand($cmd, $handler= '')
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static imageMagickCommand($command, $parameters, $path= '')
static unQuoteFilenames($parameters, $unQuote=false)
static exec($command, &$output=null, &$returnValue=0)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static getPaths($addInvalid=false)
static getCommand($cmd, $handler= '', $handlerOpt= '')