[FEATURE] Allow .ts file extension for static typoscript templates
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_svbase.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
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 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Parent class for "Services" classes
29 *
30 * TODO: temp files are not removed
31 *
32 * @author René Fritz <r.fritz@colorcube.de>
33 */
34
35 // General error - something went wrong
36 define ('T3_ERR_SV_GENERAL', -1);
37 // During execution it showed that the service is not available and should be ignored. The service itself should call $this->setNonAvailable()
38 define ('T3_ERR_SV_NOT_AVAIL', -2);
39 // Passed subtype is not possible with this service
40 define ('T3_ERR_SV_WRONG_SUBTYPE', -3);
41 // Passed subtype is not possible with this service
42 define ('T3_ERR_SV_NO_INPUT', -4);
43 // File not found which the service should process
44 define ('T3_ERR_SV_FILE_NOT_FOUND', -20);
45 // File not readable
46 define ('T3_ERR_SV_FILE_READ', -21);
47 // File not writable
48 define ('T3_ERR_SV_FILE_WRITE', -22);
49 // Passed subtype is not possible with this service
50 define ('T3_ERR_SV_PROG_NOT_FOUND', -40);
51 // Passed subtype is not possible with this service
52 define ('T3_ERR_SV_PROG_FAILED', -41);
53
54 /**
55 * Parent class for "Services" classes
56 *
57 * @author René Fritz <r.fritz@colorcube.de>
58 * @package TYPO3
59 * @subpackage t3lib
60 */
61 abstract class t3lib_svbase {
62
63 /**
64 * @var array service description array
65 */
66 var $info = array();
67
68 /**
69 * @var array error stack
70 */
71 var $error = array();
72
73 /**
74 * @var bool Defines if debug messages should be written with t3lib_div::devLog
75 */
76 var $writeDevLog = FALSE;
77
78 /**
79 * @var string The output content. That's what the services produced as result.
80 */
81 var $out = '';
82
83 /**
84 * @var string The file that should be processed.
85 */
86 var $inputFile = '';
87
88 /**
89 * @var string The content that should be processed.
90 */
91 var $inputContent = '';
92
93 /**
94 * @var string The type of the input content (or file). Might be the same as the service subtypes.
95 */
96 var $inputType = '';
97
98 /**
99 * @var string The file where the output should be written to.
100 */
101 var $outputFile = '';
102
103 /**
104 * Temporary files which have to be deleted
105 *
106 * @private
107 */
108 var $tempFiles = array();
109
110 /** @var string Prefix for temporary files */
111 protected $prefixId = '';
112
113 /***************************************
114 *
115 * Get service meta information
116 *
117 ***************************************/
118
119 /**
120 * Returns internal information array for service
121 *
122 * @return array Service description array
123 */
124 function getServiceInfo() {
125 return $this->info;
126 }
127
128 /**
129 * Returns the service key of the service
130 *
131 * @return string Service key
132 */
133 function getServiceKey() {
134 return $this->info['serviceKey'];
135 }
136
137 /**
138 * Returns the title of the service
139 *
140 * @return string Service title
141 */
142 function getServiceTitle() {
143 return $this->info['title'];
144 }
145
146 /**
147 * Returns service configuration values from the $TYPO3_CONF_VARS['SVCONF'] array
148 *
149 * @param string $optionName Name of the config option
150 * @param mixed $defaultValue Default configuration if no special config is available
151 * @param boolean $includeDefaultConfig If set the 'default' config will be returned if no special config for this service is available (default: TRUE)
152 * @return mixed Configuration value for the service
153 */
154 function getServiceOption($optionName, $defaultValue = '', $includeDefaultConfig = TRUE) {
155 $config = NULL;
156
157 $svOptions = $GLOBALS['TYPO3_CONF_VARS']['SVCONF'][$this->info['serviceType']];
158
159 if (isset($svOptions[$this->info['serviceKey']][$optionName])) {
160 $config = $svOptions[$this->info['serviceKey']][$optionName];
161 } elseif ($includeDefaultConfig && isset($svOptions['default'][$optionName])) {
162 $config = $svOptions['default'][$optionName];
163 }
164 if (!isset($config)) {
165 $config = $defaultValue;
166 }
167 return $config;
168 }
169
170 /***************************************
171 *
172 * Error handling
173 *
174 ***************************************/
175
176 /**
177 * Logs debug messages to t3lib_div::devLog()
178 *
179 * @param string $msg Debug message
180 * @param integer $severity Severity: 0 is info, 1 is notice, 2 is warning, 3 is fatal error, -1 is "OK" message
181 * @param array|boolean $dataVar dditional data you want to pass to the logger.
182 * @return void
183 */
184 function devLog($msg, $severity = 0, $dataVar = FALSE) {
185 if ($this->writeDevLog) {
186 t3lib_div::devLog($msg, $this->info['serviceKey'], $severity, $dataVar);
187 }
188 }
189
190 /**
191 * Puts an error on the error stack. Calling without parameter adds a general error.
192 *
193 * @param integer $errNum Error number (see T3_ERR_SV_* constants)
194 * @param string $errMsg Error message
195 * @return void
196 */
197 function errorPush($errNum = T3_ERR_SV_GENERAL, $errMsg = 'Unspecified error occured') {
198 array_push($this->error, array('nr' => $errNum, 'msg' => $errMsg));
199
200 if (is_object($GLOBALS['TT'])) {
201 $GLOBALS['TT']->setTSlogMessage($errMsg, 2);
202 }
203
204 }
205
206 /**
207 * Removes the last error from the error stack.
208 *
209 * @return void
210 */
211 function errorPull() {
212 array_pop($this->error);
213
214 // pop for $GLOBALS['TT']->setTSlogMessage is not supported
215 }
216
217 /**
218 * Returns the last error number from the error stack.
219 *
220 * @return integer|boolean Error number (or TRUE if no error)
221 */
222 function getLastError() {
223 // Means all is ok - no error
224 $lastError = TRUE;
225 if (count($this->error)) {
226 $error = end($this->error);
227 $lastError = $error['nr'];
228 }
229 return $lastError;
230 }
231
232 /**
233 * Returns the last message from the error stack.
234 *
235 * @return string Error message
236 */
237 function getLastErrorMsg() {
238 $lastErrorMessage = '';
239 if (count($this->error)) {
240 $error = end($this->error);
241 $lastErrorMessage = $error['msg'];
242 }
243 return $lastErrorMessage;
244 }
245
246 /**
247 * Returns all error messages as array.
248 *
249 * @return array Error messages
250 */
251 function getErrorMsgArray() {
252 $errArr = array();
253
254 if (count($this->error)) {
255 foreach ($this->error as $error) {
256 $errArr[] = $error['msg'];
257 }
258 }
259 return $errArr;
260 }
261
262
263 /**
264 * Returns the last array from the error stack.
265 *
266 * @return array Error number and message
267 */
268 function getLastErrorArray() {
269 return end($this->error);
270 }
271
272 /**
273 * Reset the error stack.
274 *
275 * @return void
276 */
277 function resetErrors() {
278 $this->error = array();
279 }
280
281 /***************************************
282 *
283 * General service functions
284 *
285 ***************************************/
286
287 /**
288 * check the availability of external programs
289 *
290 * @param string $progList Comma list of programs 'perl,python,pdftotext'
291 * @return boolean Return FALSE if one program was not found
292 */
293 function checkExec($progList) {
294 $ret = TRUE;
295
296 $progList = t3lib_div::trimExplode(',', $progList, 1);
297 foreach ($progList as $prog) {
298 if (!t3lib_exec::checkCommand($prog)) {
299 // Program not found
300 $this->errorPush(T3_ERR_SV_PROG_NOT_FOUND, 'External program not found: ' . $prog);
301 $ret = FALSE;
302 }
303 }
304 return $ret;
305 }
306
307
308 /**
309 * Deactivate the service. Use this if the service fails at runtime and will not be available.
310 *
311 * @return void
312 */
313 function deactivateService() {
314 t3lib_extMgm::deactivateService($this->info['serviceType'], $this->info['serviceKey']);
315 }
316
317 /***************************************
318 *
319 * IO tools
320 *
321 ***************************************/
322
323 /**
324 * Check if a file exists and is readable.
325 *
326 * @param string $absFile File name with absolute path.
327 * @return string|boolean File name or FALSE.
328 */
329 function checkInputFile($absFile) {
330 $checkResult = FALSE;
331 if (t3lib_div::isAllowedAbsPath($absFile) && @is_file($absFile)) {
332 if (@is_readable($absFile)) {
333 $checkResult = $absFile;
334 } else {
335 $this->errorPush(T3_ERR_SV_FILE_READ, 'File is not readable: ' . $absFile);
336 }
337 } else {
338 $this->errorPush(T3_ERR_SV_FILE_NOT_FOUND, 'File not found: ' . $absFile);
339 }
340 return $checkResult;
341 }
342
343 /**
344 * Read content from a file a file.
345 *
346 * @param string $absFile File name to read from.
347 * @param integer $length Maximum length to read. If empty the whole file will be read.
348 * @return string|boolean $content or FALSE
349 */
350 function readFile($absFile, $length = 0) {
351 $out = FALSE;
352
353 if ($this->checkInputFile($absFile)) {
354 $out = file_get_contents($absFile);
355 if ($out === FALSE) {
356 $this->errorPush(T3_ERR_SV_FILE_READ, 'Can not read from file: ' . $absFile);
357 }
358 }
359 return $out;
360 }
361
362 /**
363 * Write content to a file.
364 *
365 * @param string $content Content to write to the file
366 * @param string $absFile File name to write into. If empty a temp file will be created.
367 * @return string|boolean File name or FALSE
368 */
369 function writeFile($content, $absFile = '') {
370 if (!$absFile) {
371 $absFile = $this->tempFile($this->prefixId);
372 }
373
374 if ($absFile && t3lib_div::isAllowedAbsPath($absFile)) {
375 if ($fd = @fopen($absFile, 'wb')) {
376 @fwrite($fd, $content);
377 @fclose($fd);
378 } else {
379 $this->errorPush(T3_ERR_SV_FILE_WRITE, 'Can not write to file: ' . $absFile);
380 $absFile = FALSE;
381 }
382 }
383
384 return $absFile;
385 }
386
387 /**
388 * Create a temporary file.
389 *
390 * @param string $filePrefix File prefix.
391 * @return string|boolean File name or FALSE
392 */
393 function tempFile($filePrefix) {
394 $absFile = t3lib_div::tempnam($filePrefix);
395 if ($absFile) {
396 $ret = $absFile;
397 $this->registerTempFile($absFile);
398 } else {
399 $ret = FALSE;
400 $this->errorPush(T3_ERR_SV_FILE_WRITE, 'Can not create temp file.');
401 }
402 return $ret;
403 }
404
405 /**
406 * Register file which should be deleted afterwards.
407 *
408 * @param string File name with absolute path.
409 * @return void
410 */
411 function registerTempFile($absFile) {
412 $this->tempFiles[] = $absFile;
413 }
414
415 /**
416 * Delete registered temporary files.
417 * @return void
418 */
419 function unlinkTempFiles() {
420 foreach ($this->tempFiles as $absFile) {
421 t3lib_div::unlink_tempfile($absFile);
422 }
423 $this->tempFiles = array();
424 }
425
426 /***************************************
427 *
428 * IO input
429 *
430 ***************************************/
431
432 /**
433 * Set the input content for service processing.
434 *
435 * @param mixed $content Input content (going into ->inputContent)
436 * @param string $type The type of the input content (or file). Might be the same as the service subtypes.
437 * @return void
438 */
439 function setInput($content, $type = '') {
440 $this->inputContent = $content;
441 $this->inputFile = '';
442 $this->inputType = $type;
443 }
444
445 /**
446 * Set the input file name for service processing.
447 *
448 * @param string $absFile File name
449 * @param string $type The type of the input content (or file). Might be the same as the service subtypes.
450 * @return void
451 */
452 function setInputFile($absFile, $type = '') {
453 $this->inputContent = '';
454 $this->inputFile = $absFile;
455 $this->inputType = $type;
456 }
457
458 /**
459 * Get the input content.
460 * Will be read from input file if needed. (That is if ->inputContent is empty and ->inputFile is not)
461 *
462 * @return mixed
463 */
464 function getInput() {
465 if ($this->inputContent == '') {
466 $this->inputContent = $this->readFile($this->inputFile);
467 }
468 return $this->inputContent;
469 }
470
471
472 /**
473 * Get the input file name.
474 * If the content was set by setContent a file will be created.
475 *
476 * @param string $createFile File name. If empty a temp file will be created.
477 * @return string File name or FALSE if no input or file error.
478 */
479 function getInputFile($createFile = '') {
480 if ($this->inputFile) {
481 $this->inputFile = $this->checkInputFile($this->inputFile);
482 } elseif ($this->inputContent) {
483 $this->inputFile = $this->writeFile($this->inputContent, $createFile);
484 }
485 return $this->inputFile;
486 }
487
488 /***************************************
489 *
490 * IO output
491 *
492 ***************************************/
493
494 /**
495 * Set the output file name.
496 *
497 * @param string $absFile File name
498 * @return void
499 */
500 function setOutputFile($absFile) {
501 $this->outputFile = $absFile;
502 }
503
504 /**
505 * Get the output content.
506 *
507 * @return mixed
508 */
509 function getOutput() {
510 if ($this->outputFile) {
511 $this->out = $this->readFile($this->outputFile);
512 }
513 return $this->out;
514 }
515
516 /**
517 * Get the output file name. If no output file is set, the ->out buffer is written to the file given by input parameter filename
518 *
519 * @param string $absFile Absolute filename to write to
520 * @return mixed
521 */
522 function getOutputFile($absFile = '') {
523 if (!$this->outputFile) {
524 $this->outputFile = $this->writeFile($this->out, $absFile);
525 }
526 return $this->outputFile;
527 }
528
529 /***************************************
530 *
531 * Service implementation
532 *
533 ***************************************/
534
535 /**
536 * Initialization of the service.
537 *
538 * The class have to do a strict check if the service is available.
539 * example: check if the perl interpreter is available which is needed to run an extern perl script.
540 *
541 * @return boolean TRUE if the service is available
542 */
543 function init() {
544 // Does not work :-( but will not hurt
545 // use it as inspiration for a service based on this class
546 register_shutdown_function(array(&$this, '__destruct'));
547 // look in makeInstanceService()
548
549 $this->reset();
550
551 // Check for external programs which are defined by $info['exec']
552 if (trim($this->info['exec'])) {
553 if (!$this->checkExec($this->info['exec'])) {
554 // Nothing todo here or?
555 }
556 }
557
558 return ($this->getLastError() === TRUE);
559 }
560
561 /**
562 * Resets the service.
563 * Will be called by init(). Should be used before every use if a service instance is used multiple times.
564 *
565 * @return void
566 */
567 function reset() {
568 $this->unlinkTempFiles();
569 $this->resetErrors();
570 $this->out = '';
571 $this->inputFile = '';
572 $this->inputContent = '';
573 $this->inputType = '';
574 $this->outputFile = '';
575 }
576
577 /**
578 * Clean up the service.
579 * Child classes should explicitly call parent::__destruct() in their destructors for this to work
580 *
581 * @return void
582 */
583 function __destruct() {
584 $this->unlinkTempFiles();
585 }
586 }
587
588 ?>