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