[BUGFIX] Some methods in t3lib_TSparser should be static
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_exec.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2002-2011 René Fritz (r.fritz@colorcube.de)
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 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24 /**
25 * t3lib_exec finds executables (programs) on Unix and Windows without knowing where they are
26 *
27 * @author René Fritz <r.fritz@colorcube.de>
28 */
29
30
31 /**
32 * returns exec command for a program
33 * or FALSE
34 *
35 * This class is meant to be used without instance:
36 * $cmd = t3lib_exec::getCommand ('awstats','perl');
37 *
38 * The data of this class is cached.
39 * That means if a program is found once it don't have to be searched again.
40 *
41 * user functions:
42 *
43 * addPaths() could be used to extend the search paths
44 * getCommand() get a command string
45 * checkCommand() returns TRUE if a command is available
46 *
47 * Search paths that are included:
48 * $TYPO3_CONF_VARS['GFX']['im_path_lzw'] or $TYPO3_CONF_VARS['GFX']['im_path']
49 * $TYPO3_CONF_VARS['SYS']['binPath']
50 * $GLOBALS['_SERVER']['PATH']
51 * '/usr/bin/,/usr/local/bin/' on Unix
52 *
53 * binaries can be preconfigured with
54 * $TYPO3_CONF_VARS['SYS']['binSetup']
55 *
56 * @author René Fritz <r.fritz@colorcube.de>
57 * @package TYPO3
58 * @subpackage t3lib
59 */
60 class t3lib_exec {
61
62 /** Tells if object is already initialized */
63 protected static $initialized = FALSE;
64
65 /**
66 * Contains application list. This is an array with the following structure:
67 * - app => file name to the application (like 'tar' or 'bzip2')
68 * - path => full path to the application without application name (like '/usr/bin/' for '/usr/bin/tar')
69 * - valid => TRUE or FALSE
70 * Array key is identical to 'app'.
71 *
72 * @var array
73 */
74 protected static $applications = array();
75
76 /**
77 * Paths where to search for applications
78 *
79 * @var array
80 */
81 protected static $paths = NULL;
82
83 /**
84 * Checks if a command is valid or not, updates global variables
85 *
86 * @param string the command that should be executed. eg: "convert"
87 * @param string executer for the command. eg: "perl"
88 * @return boolean FALSE if cmd is not found, or -1 if the handler is not found
89 */
90 public static function checkCommand($cmd, $handler = '') {
91 if (!self::init()) {
92 return FALSE;
93 }
94
95 if ($handler && !self::checkCommand($handler)) {
96 return -1;
97 }
98 // Already checked and valid
99 if (self::$applications[$cmd]['valid']) {
100 return TRUE;
101 }
102 // Is set but was (above) not TRUE
103 if (isset(self::$applications[$cmd]['valid'])) {
104 return FALSE;
105 }
106
107 foreach (self::$paths as $path => $validPath) {
108 // Ignore invalid (FALSE) paths
109 if ($validPath) {
110 if (TYPO3_OS == 'WIN') {
111 // Windows OS
112 // TODO Why is_executable() is not called here?
113 if (@is_file($path . $cmd)) {
114 self::$applications[$cmd]['app'] = $cmd;
115 self::$applications[$cmd]['path'] = $path;
116 self::$applications[$cmd]['valid'] = TRUE;
117 return TRUE;
118 }
119 if (@is_file($path . $cmd . '.exe')) {
120 self::$applications[$cmd]['app'] = $cmd . '.exe';
121 self::$applications[$cmd]['path'] = $path;
122 self::$applications[$cmd]['valid'] = TRUE;
123 return TRUE;
124 }
125 } else {
126 // Unix-like OS
127 $filePath = realpath($path . $cmd);
128 if ($filePath && @is_executable($filePath)) {
129 self::$applications[$cmd]['app'] = $cmd;
130 self::$applications[$cmd]['path'] = $path;
131 self::$applications[$cmd]['valid'] = TRUE;
132 return TRUE;
133 }
134 }
135 }
136 }
137
138 // Try to get the executable with the command 'which'.
139 // It does the same like already done, but maybe on other paths
140 if (TYPO3_OS != 'WIN') {
141 $cmd = @t3lib_utility_Command::exec('which ' . $cmd);
142 if (@is_executable($cmd)) {
143 self::$applications[$cmd]['app'] = $cmd;
144 self::$applications[$cmd]['path'] = dirname($cmd) . '/';
145 self::$applications[$cmd]['valid'] = TRUE;
146 return TRUE;
147 }
148 }
149
150 return FALSE;
151 }
152
153
154 /**
155 * Returns a command string for exec(), system()
156 *
157 * @param string the command that should be executed. eg: "convert"
158 * @param string handler (executor) for the command. eg: "perl"
159 * @param string options for the handler, like '-w' for "perl"
160 * @return mixed returns command string, or FALSE if cmd is not found, or -1 if the handler is not found
161 */
162 public static function getCommand($cmd, $handler = '', $handlerOpt = '') {
163 if (!self::init()) {
164 return FALSE;
165 }
166
167 // handler
168 if ($handler) {
169 $handler = self::getCommand($handler);
170
171 if (!$handler) {
172 return -1;
173 }
174 $handler .= ' ' . $handlerOpt . ' ';
175 }
176
177 // command
178 if (!self::checkCommand($cmd)) {
179 return FALSE;
180 }
181 $cmd = self::$applications[$cmd]['path'] . self::$applications[$cmd]['app'] . ' ';
182
183 return trim($handler . $cmd);
184 }
185
186
187 /**
188 * Extend the preset paths. This way an extension can install an executable and provide the path to t3lib_exec.
189 *
190 * @param string comma separated list of extra paths where a command should be searched. Relative paths (without leading "/") are prepend with site root path (PATH_site).
191 * @return void
192 */
193 public static function addPaths($paths) {
194 self::initPaths($paths);
195 }
196
197
198 /**
199 * Returns an array of search paths
200 *
201 * @param boolean If set the array contains invalid path too. Then the key is the path and the value is empty
202 * @return array Array of search paths (empty if exec is disabled)
203 */
204 public static function getPaths($addInvalid = FALSE) {
205 if (!self::init()) {
206 return array();
207 }
208
209 $paths = self::$paths;
210
211 if (!$addInvalid) {
212 foreach ($paths as $path => $validPath) {
213 if (!$validPath) {
214 unset($paths[$path]);
215 }
216 }
217 }
218 return $paths;
219 }
220
221
222 /**
223 * Initializes this class
224 *
225 * @return void
226 */
227 protected static function init() {
228 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['disable_exec_function']) {
229 return FALSE;
230 }
231 if (!self::$initialized) {
232 self::initPaths();
233 self::$applications = self::getConfiguredApps();
234 self::$initialized = TRUE;
235 }
236 return TRUE;
237 }
238
239
240 /**
241 * Initializes and extends the preset paths with own
242 *
243 * @param string Comma seperated list of extra paths where a command should be searched. Relative paths (without leading "/") are prepend with site root path (PATH_site).
244 * @return void
245 */
246 protected static function initPaths($paths = '') {
247 $doCheck = FALSE;
248
249 // init global paths array if not already done
250 if (!is_array(self::$paths)) {
251 self::$paths = self::getPathsInternal();
252 $doCheck = TRUE;
253 }
254 // merge the submitted paths array to the global
255 if ($paths) {
256 $paths = t3lib_div::trimExplode(',', $paths, 1);
257 if (is_array($paths)) {
258 foreach ($paths as $path) {
259 // make absolute path of relative
260 if (!preg_match('#^/#', $path)) {
261 $path = PATH_site . $path;
262 }
263 if (!isset(self::$paths[$path])) {
264 if (@is_dir($path)) {
265 self::$paths[$path] = $path;
266 } else {
267 self::$paths[$path] = FALSE;
268 }
269 }
270 }
271 }
272 }
273 // check if new paths are invalid
274 if ($doCheck) {
275 foreach (self::$paths as $path => $valid) {
276 // ignore invalid (FALSE) paths
277 if ($valid AND !@is_dir($path)) {
278 self::$paths[$path] = FALSE;
279 }
280 }
281 }
282 }
283
284
285 /**
286 * Processes and returns the paths from $GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']
287 *
288 * @return array Array of commands and path
289 */
290 protected static function getConfiguredApps() {
291 $cmdArr = array();
292
293 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']) {
294 $pathSetup = preg_split('/[\n,]+/', $GLOBALS['TYPO3_CONF_VARS']['SYS']['binSetup']);
295 foreach ($pathSetup as $val) {
296 list($cmd, $cmdPath) = t3lib_div::trimExplode('=', $val, 1);
297 $cmdArr[$cmd]['app'] = basename($cmdPath);
298 $cmdArr[$cmd]['path'] = dirname($cmdPath) . '/';
299 $cmdArr[$cmd]['valid'] = TRUE;
300 }
301 }
302
303 return $cmdArr;
304 }
305
306
307 /**
308 * Sets the search paths from different sources, internal
309 *
310 * @return array Array of absolute paths (keys and values are equal)
311 */
312 protected static function getPathsInternal() {
313
314 $pathsArr = array();
315 $sysPathArr = array();
316
317 // image magick paths first
318 // im_path_lzw take precedence over im_path
319 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']))) {
320 $imPath = self::fixPath($imPath);
321 $pathsArr[$imPath] = $imPath;
322 }
323
324 // add configured paths
325 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath']) {
326 $sysPath = t3lib_div::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['binPath'], 1);
327 foreach ($sysPath as $val) {
328 $val = self::fixPath($val);
329 $sysPathArr[$val] = $val;
330 }
331 }
332
333
334 // add path from environment
335 // TODO: how does this work for WIN
336 if ($GLOBALS['_SERVER']['PATH']) {
337 $sep = (TYPO3_OS == 'WIN' ? ';' : ':');
338 $envPath = t3lib_div::trimExplode($sep, $GLOBALS['_SERVER']['PATH'], 1);
339 foreach ($envPath as $val) {
340 $val = self::fixPath($val);
341 $sysPathArr[$val] = $val;
342 }
343 }
344
345 // Set common paths for Unix (only)
346 if (TYPO3_OS !== 'WIN') {
347 $sysPathArr = array_merge($sysPathArr, array(
348 '/usr/bin/' => '/usr/bin/',
349 '/usr/local/bin/' => '/usr/local/bin/',
350 ));
351 }
352
353 $pathsArr = array_merge($pathsArr, $sysPathArr);
354
355 return $pathsArr;
356 }
357
358
359 /**
360 * Set a path to the right format
361 *
362 * @param string Input path
363 * @return string Output path
364 */
365 protected static function fixPath($path) {
366 return str_replace('//', '/', $path . '/');
367 }
368 }
369
370 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_exec.php'])) {
371 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_exec.php']);
372 }
373 ?>