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