*** empty log message ***
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_extfilefunc.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2004 Kasper Skaarhoj (kasper@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 * extending class to class t3lib_basicFileFunctions
29 *
30 * $Id$
31 *
32 * @author Kasper Skaarhoj <kasper@typo3.com>
33 */
34 /**
35 * [CLASS/FUNCTION INDEX of SCRIPT]
36 *
37 *
38 *
39 * 123: class t3lib_extFileFunctions extends t3lib_basicFileFunctions
40 * 157: function start($data)
41 * 183: function init_actionPerms($setup)
42 * 216: function mapData($inputArray)
43 * 225: function processData()
44 * 274: function printLogErrorMessages($redirect)
45 * 343: function findRecycler($theFile)
46 *
47 * SECTION: File operation functions
48 * 385: function func_upload($cmds)
49 * 427: function func_copy($cmds)
50 * 517: function func_move($cmds)
51 * 608: function func_delete($cmds)
52 * 674: function func_rename($cmds)
53 * 722: function func_newfolder($cmds)
54 * 756: function func_unzip($cmds)
55 * 791: function func_newfile($cmds)
56 * 829: function func_edit($cmds)
57 * 878: function writeLog($action,$error,$details_nr,$details,$data)
58 *
59 * TOTAL FUNCTIONS: 16
60 * (This index is automatically created/updated by the extension "extdeveval")
61 *
62 */
63
64
65
66
67
68
69
70
71
72
73
74
75
76 /**
77 * COMMENT:
78 *
79 * see basicFileFunctions
80 * see tce_file.php for SYNTAX!
81 *
82 * This class contains functions primarily used by tce_file.php (Typo Core Engine for filemanipulation)
83 * Functions include copying, moving, deleting, uploading and so on...
84 *
85 * Important internal variables:
86 *
87 * $filemounts (see basicFileFunctions)
88 * $f_ext (see basicFileFunctions)
89 * ... All fileoperations must be within the filemount-paths. Further the fileextension MUST validate true with the f_ext array
90 *
91 * $actionPerms : This array is self-explaning (look in the class below). It grants access to the functions. This could be set from outside in order to enabled functions to users. see also the function init_actionPerms() which takes input directly from the user-record
92 * $maxCopyFileSize = 10000; // max copy size for files
93 * $maxMoveFileSize = 10000; // max move size for files
94 * $maxUploadFileSize = 10000; // max upload size for files. Remember that PHP has an inner limit often set to 2 MB
95 *
96 * $recyclerFN='_recycler_' : This is regarded to be the recycler folder
97 *
98 * The unzip-function allows unzip only if the destination path has it's f_ext[]['allow'] set to '*'!!
99 * You are allowed to copy/move folders within the same 'space' (web/ftp).
100 * You are allowed to copy/move folders between spaces (web/ftp) IF the destination has it's f_ext[]['allow'] set to '*'!
101 *
102 *
103 * Advice:
104 * You should always exclude php-files from the webspace. This will keep people from uploading, copy/moving and renaming files to the php3/php-extension.
105 * You should never mount a ftp_space 'below' the webspace so that it reaches into the webspace. This is because if somebody unzips a zip-file in the ftp-space so that it reaches out into the webspace this will be a violation of the safety
106 * Eg. THIS IS A BAD IDEA: you have an ftp-space that is '/www/' and a web-space that is '/www/htdocs/'
107 *
108 *
109 *
110 * Dependencies:
111 * t3lib_div
112 * t3lib_basicfilefunctions
113 */
114
115 /**
116 * Contains functions for performing file operations like copying, pasting, uploading, moving, deleting etc. through the TCE
117 * Extending class to class t3lib_basicFileFunctions.
118 *
119 * @author Kasper Skaarhoj <kasper@typo3.com>
120 * @package TYPO3
121 * @subpackage t3lib
122 */
123 class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
124 var $maxCopyFileSize = 10000; // kb
125 var $maxMoveFileSize = 10000; // kb
126 var $maxUploadFileSize = 10000; // kb
127 var $unzipPath = ''; // Path to unzip-program (with trailing '/')
128 var $dontCheckForUnique=0; // If set, the uploaded files will overwrite existing files.
129
130 var $actionPerms = Array(
131 'deleteFile' => 0, // Deleting files physically
132 'deleteFolder' => 0, // Deleting foldes physically
133 'deleteFolderRecursively' => 0, // normally folders are deleted by the PHP-function rmdir(), but with this option a user deletes with 'rm -Rf ....' which is pretty wild!
134 'moveFile' => 0,
135 'moveFolder' => 0,
136 'copyFile' => 0,
137 'copyFolder' => 0,
138 'newFolder' => 0,
139 'newFile' => 0,
140 'editFile' => 0,
141 'unzipFile' => 0,
142 'uploadFile' => 0,
143 'renameFile' => 0,
144 'renameFolder' => 0
145 );
146
147 var $recyclerFN = '_recycler_';
148 var $useRecycler = 1; // 0 = no, 1 = if available, 2 = always
149 var $PHPFileFunctions=0; // If set, all fileoperations are done by the default PHP-functions. This is necessary under windows! On UNIX the system commands by exec() can be used unless safe_mode is enabled
150 var $dont_use_exec_commands=0; // This is necessary under windows!
151
152
153 /**
154 * @param [type] $data: ...
155 * @return [type] ...
156 */
157 function start($data) {
158 if (TYPO3_OS=='WIN' || $GLOBALS['TYPO3_CONF_VARS']['BE']['disable_exec_function']) {
159 $this->PHPFileFunctions=1;
160 $this->dont_use_exec_commands=1;
161 } else {
162 $this->PHPFileFunctions = $GLOBALS['TYPO3_CONF_VARS']['BE']['usePHPFileFunctions'];
163 }
164 $this->data = $data;
165 $this->datamap = $this->mapData($this->data);
166 $this->unzipPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'];
167
168 $maxFileSize=intval($GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize']);
169 if ($maxFileSize>0) {
170 $this->maxCopyFileSize = $maxFileSize;
171 $this->maxMoveFileSize = $maxFileSize;
172 $this->maxUploadFileSize = $maxFileSize;
173 }
174 }
175
176 /**
177 * Sets up permission to perform file/directory operations.
178 * See below or the be_user-table for the significanse of the various bits in $setup ($BE_USER->user['fileoper_perms'])
179 *
180 * @param [type] $setup: ...
181 * @return [type] ...
182 */
183 function init_actionPerms($setup) {
184 if (($setup&1)==1) { // Files: Upload,Copy,Move,Delete,Rename
185 $this->actionPerms['uploadFile']=1;
186 $this->actionPerms['copyFile']=1;
187 $this->actionPerms['moveFile']=1;
188 $this->actionPerms['deleteFile']=1;
189 $this->actionPerms['renameFile']=1;
190 $this->actionPerms['editFile']=1;
191 $this->actionPerms['newFile']=1;
192 }
193 if (($setup&2)==2) { // Files: Unzip
194 $this->actionPerms['unzipFile']=1;
195 }
196 if (($setup&4)==4) { // Directory: Move,Delete,Rename,New
197 $this->actionPerms['moveFolder']=1;
198 $this->actionPerms['deleteFolder']=1;
199 $this->actionPerms['renameFolder']=1;
200 $this->actionPerms['newFolder']=1;
201 }
202 if (($setup&8)==8) { // Directory: Copy
203 $this->actionPerms['copyFolder']=1;
204 }
205 if (($setup&16)==16) { // Directory: Delete recursively (rm -Rf)
206 $this->actionPerms['deleteFolderRecursively']=1;
207 }
208 }
209
210 /**
211 * If PHP4 then we just set the incoming data to the arrays as PHP4 submits multidimensional arrays
212 *
213 * @param [type] $inputArray: ...
214 * @return [type] ...
215 */
216 function mapData($inputArray) {
217 if (is_array($inputArray)) {
218 return $inputArray;
219 }
220 }
221
222 /**
223 * @return [type] ...
224 */
225 function processData() {
226 if (!$this->isInit) return false;
227 if (is_array($this->datamap)) {
228 #t3lib_div::stripSlashesOnArray($this->datamap); // NOT needed anymore since $this->datamap is required to be stripped already!
229
230 reset($this->datamap);
231 while (list($action, $content) = each($this->datamap)) {
232 if (is_array($content)) {
233 while(list($id, $cmdArr) = each($content)) {
234 clearstatcache();
235 switch ($action) {
236 case 'delete':
237 $this->func_delete($cmdArr);
238 break;
239 case 'copy':
240 $this->func_copy($cmdArr);
241 break;
242 case 'move':
243 $this->func_move($cmdArr);
244 break;
245 case 'rename':
246 $this->func_rename($cmdArr);
247 break;
248 case 'newfolder':
249 $this->func_newfolder($cmdArr);
250 break;
251 case 'newfile':
252 $this->func_newfile($cmdArr);
253 break;
254 case 'editfile':
255 $this->func_edit($cmdArr);
256 break;
257 case 'upload':
258 $this->func_upload($cmdArr);
259 break;
260 case 'unzip':
261 $this->func_unzip($cmdArr);
262 break;
263 }
264 }
265 }
266 }
267 }
268 }
269
270 /**
271 * @param [type] $redirect: ...
272 * @return [type] ...
273 */
274 function printLogErrorMessages($redirect) {
275
276 $res_log = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
277 '*',
278 'sys_log',
279 'type=2 AND userid='.intval($GLOBALS['BE_USER']->user['uid']).' AND tstamp='.intval($GLOBALS['EXEC_TIME']).' AND error!=0'
280 );
281 $errorJS = array();
282 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res_log)) {
283 $log_data = unserialize($row['log_data']);
284 $errorJS[] = $row[error].': '.sprintf($row['details'], $log_data[0],$log_data[1],$log_data[2],$log_data[3],$log_data[4]);
285 }
286
287 if (count($errorJS)) {
288 $error_doc = t3lib_div::makeInstance('template');
289 $error_doc->backPath = '';
290
291 $content.=$error_doc->startPage('tce_db.php Error output');
292
293 $lines[]='<tr class="bgColor5"><td colspan=2 align=center><strong>Errors:</strong></td></tr>';
294 reset($errorJS);
295 while(list(,$line)=each($errorJS)) {
296 $lines[]='<tr class="bgColor4"><td valign=top><img'.t3lib_iconWorks::skinImg('','gfx/icon_fatalerror.gif','width="18" height="16"').' alt="" /></td><td>'.htmlspecialchars($line).'</td></tr>';
297 }
298
299 $lines[]='<tr><td colspan=2 align=center><BR><form action=""><input type="submit" value="Continue" onClick="document.location=\''.$redirect.'\';return false;"></form></td></tr>';
300 $content.= '<BR><BR><table border=0 cellpadding=1 cellspacing=1 width=300 align=center>'.implode('',$lines).'</table>';
301 $content.= $error_doc->endPage();
302 echo $content;
303 exit;
304 } else {
305
306 t3lib_BEfunc::getSetUpdateSignal('updateFolderTree');
307
308 if ($redirect) {
309 header('Location: '.t3lib_div::locationHeaderUrl($redirect));
310 exit;
311 }
312
313 echo '
314 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
315 <html>
316 <head>
317 <title>File Status script</title>
318 </head>
319 <body bgcolor="#F7F3EF">
320
321 <script language="javascript" type="text/javascript">
322 if (top.busy) {
323 top.busy.loginRefreshed();
324 }
325 top.goToModule("file_list");
326 </script>
327 </body>
328 </html>
329 ';
330 exit;
331 }
332 }
333
334 /**
335 * Takes a valid Path ($theFile)
336 * Goes back in the path and checks in each directory if a folder named $this->recyclerFN (usually '_recycler_') is present.
337 * Returns the path (without trailing slash) of the closest recycle-folder if found. Else false.
338 * If a folder in the tree happens to be a _recycler_-folder (which means that we're deleting something inside a _recycler_-folder) this is ignored
339 *
340 * @param [type] $theFile: ...
341 * @return [type] ...
342 */
343 function findRecycler($theFile) {
344 if ($this->isPathValid($theFile)) {
345 $theFile=$this->cleanDirectoryName($theFile);
346 $fI=t3lib_div::split_fileref($theFile);
347 $c=0;
348 while($this->checkPathAgainstMounts($fI['path']) && $c<20) {
349 $rDir = $fI['path'].$this->recyclerFN;
350 if (@is_dir($rDir) && $this->recyclerFN!=$fI['file']) {
351 return $rDir;
352 }
353 $theFile=$fI['path'];
354 $theFile=$this->cleanDirectoryName($theFile);
355 $fI=t3lib_div::split_fileref($theFile);
356 $c++;
357 }
358 }
359 }
360
361
362
363
364
365
366
367
368
369
370 /*************************************
371 *
372 * File operation functions
373 *
374 **************************************/
375
376 /**
377 * Upload of files (action=1)
378 * $cmds['data'] is the ID-number (points to the global var that holds the filename-ref ($GLOBALS['HTTP_POST_FILES']['upload_'.$id]['name'])
379 * $cmds['target'] is the target directory
380 * Returns the new filename upon success
381 *
382 * @param [type] $cmds: ...
383 * @return [type] ...
384 */
385 function func_upload($cmds) {
386 if (!$this->isInit) return false;
387 $id = $cmds['data'];
388 if ($GLOBALS['HTTP_POST_FILES']['upload_'.$id]['name']) {
389 $theFile = $GLOBALS['HTTP_POST_FILES']['upload_'.$id]['tmp_name']; // filename of the uploaded file
390 $theFileSize = $GLOBALS['HTTP_POST_FILES']['upload_'.$id]['size']; // filesize of the uploaded file
391 $theName = $this->cleanFileName(stripslashes($GLOBALS['HTTP_POST_FILES']['upload_'.$id]['name'])); // The original filename
392 if (is_uploaded_file($theFile) && $theName) { // Check the file
393 if ($this->actionPerms['uploadFile']) {
394 if ($theFileSize<($this->maxUploadFileSize*1024)) {
395 $fI = t3lib_div::split_fileref($theName);
396 $theTarget = $this->is_directory($cmds['target']); // Check the target dir
397 if ($theTarget && $this->checkPathAgainstMounts($theTarget.'/')) {
398 if ($this->checkIfAllowed($fI['fileext'], $theTarget, $fI['file'])) {
399 $theNewFile = $this->getUniqueName($theName, $theTarget, $this->dontCheckForUnique);
400 if ($theNewFile) {
401 t3lib_div::upload_copy_move($theFile,$theNewFile);
402
403 clearstatcache();
404 if (@is_file($theNewFile)) {
405 $this->writelog(1,0,1,"Uploading file '%s' to '%s'",Array($theName,$theNewFile, $id));
406 return $theNewFile;
407 } else $this->writelog(1,1,100,"Uploaded file could not be moved! Write-permission problem in '%s'?",Array($theTarget.'/'));
408 } else $this->writelog(1,1,101,"No unique filename available in '%s'!",Array($theTarget.'/'));
409 } else $this->writelog(1,1,102,"Fileextension '%s' is not allowed in '%s'!",Array($fI['fileext'],$theTarget.'/'));
410 } else $this->writelog(1,1,103,"Destination path '%s' was not within your mountpoints!",Array($theTarget.'/'));
411 } else $this->writelog(1,1,104,"The uploaded file exceeds the size-limit of %s bytes",Array($this->maxUploadFileSize*1024));
412 } else $this->writelog(1,1,105,"You are not allowed to upload files!",'');
413 } else $this->writelog(1,2,106,'The uploaded file did not exist!','');
414 }
415 }
416
417 /**
418 * Copying files and folders (action=2)
419 * $cmds['data'] is the the file/folder to copy
420 * $cmds['target'] is the path where to copy to
421 * $cmds['altName'] (boolean): If set, another filename is found in case the target already exists
422 * Returns the new filename upon success
423 *
424 * @param [type] $cmds: ...
425 * @return [type] ...
426 */
427 function func_copy($cmds) {
428 if (!$this->isInit) return false;
429 $theFile = $cmds['data'];
430 $theDest = $this->is_directory($cmds['target']); // Clean up destination directory
431 $altName = $cmds['altName'];
432 if (!$theDest) {
433 $this->writelog(2,2,100,"Destination '%s' was not a directory",Array($cmds['target']));
434 return false;
435 }
436 if (!$this->isPathValid($theFile) || !$this->isPathValid($theDest)) {
437 $this->writelog(2,2,101,"Target or destination had invalid path ('..' and '//' is not allowed in path). T='%s', D='%s'",Array($theFile,$theDest));
438 return false;
439 }
440 if (@is_file($theFile)) { // If we are copying a file...
441 if ($this->actionPerms['copyFile']) {
442 if (filesize($theFile) < ($this->maxCopyFileSize*1024)) {
443 $fI=t3lib_div::split_fileref($theFile);
444 if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
445 $theDestFile=$this->getUniqueName($fI['file'], $theDest);
446 $fI=t3lib_div::split_fileref($theDestFile);
447 } else {
448 $theDestFile=$theDest.'/'.$fI['file'];
449 }
450 if ($theDestFile && !@file_exists($theDestFile)) {
451 if ($this->checkIfAllowed($fI['fileext'], $theDest, $fI['file'])) {
452 if ($this->checkPathAgainstMounts($theDestFile) && $this->checkPathAgainstMounts($theFile)) {
453 if ($this->PHPFileFunctions) {
454 copy ($theFile,$theDestFile);
455 } else {
456 $cmd = 'cp "'.$theFile.'" "'.$theDestFile.'"';
457 exec($cmd);
458 }
459 clearstatcache();
460 if (@is_file($theDestFile)) {
461 $this->writelog(2,0,1,"File '%s' copied to '%s'",Array($theFile,$theDestFile));
462 return $theDestFile;
463 } else $this->writelog(2,2,109,"File '%s' WAS NOT copied to '%s'! Write-permission problem?",Array($theFile,$theDestFile));
464 } else $this->writelog(2,1,110,"Target or destination was not within your mountpoints! T='%s', D='%s'",Array($theFile,$theDestFile));
465 } else $this->writelog(2,1,111,"Fileextension '%s' is not allowed in '%s'!",Array($fI['fileext'],$theDest.'/'));
466 } else $this->writelog(2,1,112,"File '%s' already exists!",Array($theDestFile));
467 } else $this->writelog(2,1,113,"File '%s' exceeds the size-limit of %s bytes",Array($theFile,$this->maxCopyFileSize*1024));
468 } else $this->writelog(2,1,114,"You are not allowed to copy files",'');
469 // FINISHED copying file
470
471 } elseif (@is_dir($theFile) && !$this->dont_use_exec_commands) { // if we're copying a folder
472 if ($this->actionPerms['copyFolder']) {
473 $theFile = $this->is_directory($theFile);
474 if ($theFile) {
475 $fI=t3lib_div::split_fileref($theFile);
476 if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
477 $theDestFile=$this->getUniqueName($fI['file'], $theDest);
478 $fI=t3lib_div::split_fileref($theDestFile);
479 } else {
480 $theDestFile=$theDest.'/'.$fI['file'];
481 }
482 if ($theDestFile && !@file_exists($theDestFile)) {
483 if (!t3lib_div::isFirstPartOfStr($theDestFile.'/',$theFile.'/')) { // Check if the one folder is inside the other or on the same level... to target/dest is the same?
484 if ($this->checkIfFullAccess($theDest) || $this->is_webPath($theDestFile)==$this->is_webPath($theFile)) { // no copy of folders between spaces
485 if ($this->checkPathAgainstMounts($theDestFile) && $this->checkPathAgainstMounts($theFile)) {
486 // No way to do this under windows!
487 $cmd = 'cp -R "'.$theFile.'" "'.$theDestFile.'"';
488 exec($cmd);
489 clearstatcache();
490 if (@is_dir($theDestFile)) {
491 $this->writelog(2,0,2,"Directory '%s' copied to '%s'",Array($theFile,$theDestFile));
492 return $theDestFile;
493 } else $this->writelog(2,2,119,"Directory '%s' WAS NOT copied to '%s'! Write-permission problem?",Array($theFile,$theDestFile));
494 } else $this->writelog(2,1,120,"Target or destination was not within your mountpoints! T='%s', D='%s'",Array($theFile,$theDestFile));
495 } else $this->writelog(2,1,121,"You don't have full access to the destination directory '%s'!",Array($theDest.'/'));
496 } else $this->writelog(2,1,122,"Destination cannot be inside the target! D='%s', T='%s'",Array($theDestFile.'/',$theFile.'/'));
497 } else $this->writelog(2,1,123,"Target '%s' already exists!",Array($theDestFile));
498 } else $this->writelog(2,2,124,"Target seemed not to be a directory! (Shouldn't happen here!)",'');
499 } else $this->writelog(2,1,125,"You are not allowed to copy directories",'');
500 // FINISHED copying directory
501
502 } else {
503 $this->writelog(2,2,130,"The item '%s' was not a file or directory!",Array($theFile));
504 }
505 }
506
507 /**
508 * Moving files and folders (action=3)
509 * $cmds['data'] is the the file/folder to move
510 * $cmds['target'] is the path where to move to
511 * $cmds['altName'] (boolean): If set, another filename is found in case the target already exists
512 * Returns the new filename upon success
513 *
514 * @param [type] $cmds: ...
515 * @return [type] ...
516 */
517 function func_move($cmds) {
518 if (!$this->isInit) return false;
519 $theFile = $cmds['data'];
520 $theDest = $this->is_directory($cmds['target']); // Clean up destination directory
521 $altName = $cmds['altName'];
522 if (!$theDest) {
523 $this->writelog(3,2,100,"Destination '%s' was not a directory",Array($cmds['target']));
524 return false;
525 }
526 if (!$this->isPathValid($theFile) || !$this->isPathValid($theDest)) {
527 $this->writelog(3,2,101,"Target or destination had invalid path ('..' and '//' is not allowed in path). T='%s', D='%s'",Array($theFile,$theDest));
528 return false;
529 }
530 if (@is_file($theFile)) { // If we are moving a file...
531 if ($this->actionPerms['moveFile']) {
532 if (filesize($theFile) < ($this->maxMoveFileSize*1024)) {
533 $fI=t3lib_div::split_fileref($theFile);
534 if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
535 $theDestFile=$this->getUniqueName($fI['file'], $theDest);
536 $fI=t3lib_div::split_fileref($theDestFile);
537 } else {
538 $theDestFile=$theDest.'/'.$fI['file'];
539 }
540 if ($theDestFile && !@file_exists($theDestFile)) {
541 if ($this->checkIfAllowed($fI['fileext'], $theDest, $fI['file'])) {
542 if ($this->checkPathAgainstMounts($theDestFile) && $this->checkPathAgainstMounts($theFile)) {
543 if ($this->PHPFileFunctions) {
544 rename($theFile, $theDestFile);
545 } else {
546 $cmd = 'mv "'.$theFile.'" "'.$theDestFile.'"';
547 exec($cmd);
548 }
549 clearstatcache();
550 if (@is_file($theDestFile)) {
551 $this->writelog(3,0,1,"File '%s' moved to '%s'",Array($theFile,$theDestFile));
552 return $theDestFile;
553 } else $this->writelog(3,2,109,"File '%s' WAS NOT moved to '%s'! Write-permission problem?",Array($theFile,$theDestFile));
554 } else $this->writelog(3,1,110,"Target or destination was not within your mountpoints! T='%s', D='%s'",Array($theFile,$theDestFile));
555 } else $this->writelog(3,1,111,"Fileextension '%s' is not allowed in '%s'!",Array($fI['fileext'],$theDest.'/'));
556 } else $this->writelog(3,1,112,"File '%s' already exists!",Array($theDestFile));
557 } else $this->writelog(3,1,113,"File '%s' exceeds the size-limit of %s bytes",Array($theFile,$this->maxMoveFileSize*1024));
558 } else $this->writelog(3,1,114,"You are not allowed to move files",'');
559 // FINISHED moving file
560
561 } elseif (@is_dir($theFile)) { // if we're moving a folder
562 if ($this->actionPerms['moveFolder']) {
563 $theFile = $this->is_directory($theFile);
564 if ($theFile) {
565 $fI=t3lib_div::split_fileref($theFile);
566 if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
567 $theDestFile=$this->getUniqueName($fI['file'], $theDest);
568 $fI=t3lib_div::split_fileref($theDestFile);
569 } else {
570 $theDestFile=$theDest.'/'.$fI['file'];
571 }
572 if ($theDestFile && !@file_exists($theDestFile)) {
573 if (!t3lib_div::isFirstPartOfStr($theDestFile.'/',$theFile.'/')) { // Check if the one folder is inside the other or on the same level... to target/dest is the same?
574 if ($this->checkIfFullAccess($theDest) || $this->is_webPath($theDestFile)==$this->is_webPath($theFile)) { // // no moving of folders between spaces
575 if ($this->checkPathAgainstMounts($theDestFile) && $this->checkPathAgainstMounts($theFile)) {
576 if ($this->PHPFileFunctions) {
577 rename($theFile, $theDestFile);
578 } else {
579 $cmd = 'mv "'.$theFile.'" "'.$theDestFile.'"';
580 exec($cmd,$errArr,$retVar);
581 }
582 clearstatcache();
583 if (@is_dir($theDestFile)) {
584 $this->writelog(3,0,2,"Directory '%s' moved to '%s'",Array($theFile,$theDestFile));
585 return $theDestFile;
586 } else $this->writelog(3,2,119,"Directory '%s' WAS NOT moved to '%s'! Write-permission problem?",Array($theFile,$theDestFile));
587 } else $this->writelog(3,1,120,"Target or destination was not within your mountpoints! T='%s', D='%s'",Array($theFile,$theDestFile));
588 } else $this->writelog(3,1,121,"You don't have full access to the destination directory '%s'!",Array($theDest.'/'));
589 } else $this->writelog(3,1,122,"Destination cannot be inside the target! D='%s', T='%s'",Array($theDestFile.'/',$theFile.'/'));
590 } else $this->writelog(3,1,123,"Target '%s' already exists!",Array($theDestFile));
591 } else $this->writelog(3,2,124,"Target seemed not to be a directory! (Shouldn't happen here!)",'');
592 } else $this->writelog(3,1,125,"You are not allowed to move directories",'');
593 // FINISHED moving directory
594
595 } else {
596 $this->writelog(3,2,130,"The item '%s' was not a file or directory!",Array($theFile));
597 }
598 }
599
600 /**
601 * Deleting files and folders (action=4)
602 * $cmds['data'] is the the file/folder to delete
603 * Returns true upon success
604 *
605 * @param [type] $cmds: ...
606 * @return [type] ...
607 */
608 function func_delete($cmds) {
609 if (!$this->isInit) return false;
610 $theFile = $cmds['data'];
611 if (!$this->isPathValid($theFile)) {
612 $this->writelog(4,2,101,"Target '%s' had invalid path ('..' and '//' is not allowed in path).",Array($theFile));
613 return false;
614 }
615 if ($this->useRecycler && $recyclerPath=$this->findRecycler($theFile)) {
616 // If a recycler is found, the deleted items is moved to the recycler and not just deleted.
617 $newCmds=Array();
618 $newCmds['data']=$theFile;
619 $newCmds['target']=$recyclerPath;
620 $newCmds['altName']=1;
621 $this->func_move($newCmds);
622 $this->writelog(4,0,4,"Item '%s' moved to recycler at '%s'",Array($theFile,$recyclerPath));
623 return true;
624 } elseif ($this->useRecycler != 2) { // if $this->useRecycler==2 then we cannot delete for real!!
625 if (@is_file($theFile)) { // If we are deleting a file...
626 if ($this->actionPerms['deleteFile']) {
627 if ($this->checkPathAgainstMounts($theFile)) {
628 if (@unlink($theFile)) {
629 $this->writelog(4,0,1,"File '%s' deleted",Array($theFile));
630 return true;
631 } else $this->writelog(4,1,110,"Could not delete file '%s'. Write-permission problem?", Array($theFile));
632 } else $this->writelog(4,1,111,"Target was not within your mountpoints! T='%s'",Array($theFile));
633 } else $this->writelog(4,1,112,"You are not allowed to delete files",'');
634 // FINISHED deleting file
635
636 } elseif (@is_dir($theFile) && !$this->dont_use_exec_commands) { // if we're deleting a folder
637 if ($this->actionPerms['deleteFolder']) {
638 $theFile = $this->is_directory($theFile);
639 if ($theFile) {
640 if ($this->checkPathAgainstMounts($theFile)) { // I choose not to append '/' to $theFile here as this will prevent us from deleting mounts!! (which makes sense to me...)
641 if ($this->actionPerms['deleteFolderRecursively']) {
642 // No way to do this under windows
643 $cmd = 'rm -Rf "'.$theFile.'"';
644 exec($cmd); // This is a quite critical command...
645 clearstatcache();
646 if (!@file_exists($theFile)) {
647 $this->writelog(4,0,2,"Directory '%s' deleted recursively!",Array($theFile));
648 return true;
649 } else $this->writelog(4,2,119,"Directory '%s' WAS NOT deleted recursively! Write-permission problem?",Array($theFile));
650 } else {
651 if (@rmdir($theFile)) {
652 $this->writelog(4,0,3,"Directory '%s' deleted",Array($theFile));
653 return true;
654 } else $this->writelog(4,1,120,"Could not delete directory! Write-permission problem? Is directory '%s' empty?",Array($theFile));
655 }
656 } else $this->writelog(4,1,121,"Target was not within your mountpoints! T='%s'",Array($theFile));
657 } else $this->writelog(4,2,122,"Target seemed not to be a directory! (Shouldn't happen here!)",'');
658 } else $this->writelog(4,1,123,"You are not allowed to delete directories",'');
659 // FINISHED copying directory
660
661 } else $this->writelog(4,2,130,"The item was not a file or directory! '%s'",Array($theFile));
662 } else $this->writelog(4,1,131,"No recycler found!",'');
663 }
664
665 /**
666 * Renaming files or foldes (action=5)
667 * $cmds['data'] is the new name
668 * $cmds['target'] is the target (file or dir)
669 * Returns the new filename upon success
670 *
671 * @param [type] $cmds: ...
672 * @return [type] ...
673 */
674 function func_rename($cmds) {
675 if (!$this->isInit) return false;
676 $theNewName = $this->cleanFileName($cmds['data']);
677 if ($theNewName) {
678 if ($this->checkFileNameLen($theNewName)) {
679 $theTarget = $cmds['target'];
680 $type = filetype($theTarget);
681 if ($type=='file' || $type=='dir') { // $type MUST BE file or dir
682 $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
683 if ($fileInfo['file']!=$theNewName) { // The name should be different from the current. And the filetype must be allowed
684 $theRenameName = $fileInfo['path'].$theNewName;
685 if ($this->checkPathAgainstMounts($fileInfo['path'])) {
686 if (!@file_exists($theRenameName)) {
687 if ($type=='file') {
688 if ($this->actionPerms['renameFile']) {
689 $fI = t3lib_div::split_fileref($theRenameName);
690 if ($this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
691 if (@rename($theTarget, $theRenameName)) {
692 $this->writelog(5,0,1,"File renamed from '%s' to '%s'",Array($fileInfo['file'],$theNewName));
693 return $theRenameName;
694 } else $this->writelog(5,1,100,"File '%s' was not renamed! Write-permission problem in '%s'?",Array($theTarget,$fileInfo['path']));
695 } else $this->writelog(5,1,101,"Fileextension '%s' was not allowed!",Array($fI['fileext']));
696 } else $this->writelog(5,1,102,"You are not allowed to rename files!",'');
697 } elseif ($type=='dir') {
698 if ($this->actionPerms['renameFolder']) {
699 if (@rename($theTarget, $theRenameName)) {
700 $this->writelog(5,0,2,"Directory renamed from '%s' to '%s'",Array($fileInfo['file'],$theNewName));
701 return $theRenameName;
702 } else $this->writelog(5,1,110,"Directory '%s' was not renamed! Write-permission problem in '%s'?",Array($theTarget,$fileInfo['path']));
703 } else $this->writelog(5,1,111,"You are not allowed to rename directories!",'');
704 }
705 } else $this->writelog(5,1,120,"Destination '%s' existed already!",Array($theRenameName));
706 } else $this->writelog(5,1,121,"Destination path '%s' was not within your mountpoints!",Array($fileInfo['path']));
707 } else $this->writelog(5,1,122,"Old and new name is the same (%s)",Array($theNewName));
708 } else $this->writelog(5,2,123,"Target '%s' was neither a directory nor a file!",Array($theTarget));
709 } else $this->writelog(5,1,124,"New name '%s' was too long (max %s characters)",Array($theNewName,$this->maxInputNameLen));
710 }
711 }
712
713 /**
714 * This creates a new folder. (action=6)
715 * $cmds['data'] is the foldername
716 * $cmds['target'] is the path where to create it
717 * Returns the new foldername upon success
718 *
719 * @param [type] $cmds: ...
720 * @return [type] ...
721 */
722 function func_newfolder($cmds) {
723 if (!$this->isInit) return false;
724 $theFolder = $this->cleanFileName($cmds['data']);
725 if ($theFolder) {
726 if ($this->checkFileNameLen($theFolder)) {
727 $theTarget = $this->is_directory($cmds['target']); // Check the target dir
728 if ($theTarget) {
729 if ($this->actionPerms['newFolder']) {
730 $theNewFolder = $theTarget.'/'.$theFolder;
731 if ($this->checkPathAgainstMounts($theNewFolder)) {
732 if (!@file_exists($theNewFolder)) {
733 if (@mkdir($theNewFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']))){
734 @chmod($theNewFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'])); //added this line, because the mode at 'mkdir' has a strange behaviour sometimes
735 $this->writelog(6,0,1,"Directory '%s' created in '%s'",Array($theFolder,$theTarget.'/'));
736 return $theNewFolder;
737 } else $this->writelog(6,1,100,"Directory '%s' not created. Write-permission problem in '%s'?",Array($theFolder,$theTarget.'/'));
738 } else $this->writelog(6,1,101,"File or directory '%s' existed already!",Array($theNewFolder));
739 } else $this->writelog(6,1,102,"Destination path '%s' was not within your mountpoints!",Array($theTarget.'/'));
740 } else $this->writelog(6,1,103,"You are not allowed to create directories!",'');
741 } else $this->writelog(6,2,104,"Destination '%s' was not a directory",Array($cmds['target']));
742 } else $this->writelog(6,1,105,"New name '%s' was too long (max %s characters)",Array($theFolder,$this->maxInputNameLen));
743 }
744 }
745
746 /**
747 * Unzipping file (action=7)
748 * This is permitted only if the user has fullAccess or if the file resides
749 * $cmds['data'] is the zip-file
750 * $cmds['target'] is the target directory. If not set we'll default to the same directory as the file is in
751 * If target is not supplied the target will be the current directory
752 *
753 * @param [type] $cmds: ...
754 * @return [type] ...
755 */
756 function func_unzip($cmds) {
757 if (!$this->isInit || $this->dont_use_exec_commands) return false;
758 $theFile = $cmds['data'];
759 if (@is_file($theFile)) {
760 $fI=t3lib_div::split_fileref($theFile);
761 if (!isset($cmds['target'])) {
762 $cmds['target'] = $fI['path'];
763 }
764 $theDest = $this->is_directory($cmds['target']); // Clean up destination directory
765 if ($theDest) {
766 if ($this->actionPerms['unzipFile']) {
767 if ($fI['fileext']=='zip') {
768 if ($this->checkIfFullAccess($theDest)) {
769 if ($this->checkPathAgainstMounts($theFile) && $this->checkPathAgainstMounts($theDest.'/')) {
770 // No way to do this under windows.
771 $cmd = $this->unzipPath.'unzip -qq "'.$theFile.'" -d "'.$theDest.'"';
772 exec($cmd);
773 $this->writelog(7,0,1,"Unzipping file '%s' in '%s'",Array($theFile,$theDest));
774 } else $this->writelog(7,1,100,"File '%s' or destination '%s' was not within your mountpoints!",Array($theFile,$theDest));
775 } else $this->writelog(7,1,101,"You don't have full access to the destination directory '%s'!",Array($theDest));
776 } else $this->writelog(7,1,102,"Fileextension is not 'zip'",'');
777 } else $this->writelog(7,1,103,"You are not allowed to unzip files",'');
778 } else $this->writelog(7,2,104,"Destination '%s' was not a directory",Array($cmds['target']));
779 } else $this->writelog(7,2,105,"The file '%s' did not exist!",Array($theFile));
780 }
781
782 /**
783 * This creates a new file. (action=8)
784 * $cmds['data'] is the new filename
785 * $cmds['target'] is the path where to create it
786 * Returns the new filename upon success
787 *
788 * @param [type] $cmds: ...
789 * @return [type] ...
790 */
791 function func_newfile($cmds) {
792 $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
793 if (!$this->isInit) return false;
794 $newName = $this->cleanFileName($cmds['data']);
795 if ($newName) {
796 if ($this->checkFileNameLen($newName)) {
797 $theTarget = $this->is_directory($cmds['target']); // Check the target dir
798 $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
799 if ($theTarget) {
800 if ($this->actionPerms['newFile']) {
801 $theNewFile = $theTarget.'/'.$newName;
802 if ($this->checkPathAgainstMounts($theNewFile)) {
803 if (!@file_exists($theNewFile)) {
804 $fI = t3lib_div::split_fileref($theNewFile);
805 if ($this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
806 if (t3lib_div::inList($extList, $fI['fileext'])) {
807 if (t3lib_div::writeFile($theNewFile,'')) {
808 clearstatcache();
809 $this->writelog(8,0,1,"File created: '%s'",Array($fI['file']));
810 } else $this->writelog(8,1,100,"File '%s' was not created! Write-permission problem in '%s'?",Array($fI['file'], $theTarget));
811 } else $this->writelog(8,1,107,"Fileextension '%s' is not a textfile format! (%s)",Array($fI['fileext'], $extList));
812 } else $this->writelog(8,1,106,"Fileextension '%s' was not allowed!",Array($fI['fileext']));
813 } else $this->writelog(8,1,101,"File '%s' existed already!",Array($theNewFile));
814 } else $this->writelog(8,1,102,"Destination path '%s' was not within your mountpoints!",Array($theTarget.'/'));
815 } else $this->writelog(8,1,103,"You are not allowed to create files!",'');
816 } else $this->writelog(8,2,104,"Destination '%s' was not a directory",Array($cmds['target']));
817 } else $this->writelog(8,1,105,"New name '%s' was too long (max %s characters)",Array($newName,$this->maxInputNameLen));
818 }
819 }
820
821 /**
822 * Editing textfiles or foldes (action=9)
823 * $cmds['data'] is the new content
824 * $cmds['target'] is the target (file or dir)
825 *
826 * @param [type] $cmds: ...
827 * @return [type] ...
828 */
829 function func_edit($cmds) {
830 if (!$this->isInit) return false;
831 $theTarget = $cmds['target'];
832 $content = $cmds['data'];
833 $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
834 $type = filetype($theTarget);
835 if ($type=='file') { // $type MUST BE file
836 $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
837 $fI =$fileInfo;
838 if ($this->checkPathAgainstMounts($fileInfo['path'])) {
839 if ($this->actionPerms['editFile']) {
840 $fI = t3lib_div::split_fileref($theTarget);
841 if ($this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
842 if (t3lib_div::inList($extList, $fileInfo['fileext'])) {
843 if (t3lib_div::writeFile($theTarget,$content)) {
844 clearstatcache();
845 $this->writelog(9,0,1,"File saved to '%s', bytes: %s, MD5: %s ",Array($fileInfo['file'],@filesize($theTarget),md5($content)));
846 } else $this->writelog(9,1,100,"File '%s' was not saved! Write-permission problem in '%s'?",Array($theTarget,$fileInfo['path']));
847 } else $this->writelog(9,1,102,"Fileextension '%s' is not a textfile format! (%s)",Array($fI['fileext'], $extList));
848 } else $this->writelog(9,1,103,"Fileextension '%s' was not allowed!",Array($fI['fileext']));
849 } else $this->writelog(9,1,104,'You are not allowed to edit files!','');
850 } else $this->writelog(9,1,121,"Destination path '%s' was not within your mountpoints!",Array($fileInfo['path']));
851 } else $this->writelog(9,2,123,"Target '%s' was not a file!",Array($theTarget));
852 }
853
854 /**
855 * Logging actions
856 *
857 * Log messages:
858 * [action]-[details_nr.]
859 *
860 * REMEMBER to UPDATE the real messages set in tools/log/localconf_log.php
861 *
862 * 9-1: File saved to '%s', bytes: %s, MD5: %s
863 *
864 * $action: The action number. See the functions in the class for a hint. Eg. edit is '9', upload is '1' ...
865 * $error: The severity: 0 = message, 1 = error, 2 = System Error, 3 = security notice (admin)
866 * $details_nr: This number is unique for every combination of $type and $action. This is the error-message number, which can later be used to translate error messages.
867 * $details: This is the default, raw error message in english
868 * $data: Array with special information that may go into $details by '%s' marks / sprintf() when the log is shown
869 *
870 * @param [type] $action: ...
871 * @param [type] $error: ...
872 * @param [type] $details_nr: ...
873 * @param [type] $details: ...
874 * @param [type] $data: ...
875 * @return [type] ...
876 * @see class.t3lib_userauthgroup.php
877 */
878 function writeLog($action,$error,$details_nr,$details,$data) {
879 $type=2; // Type value for tce_file.php
880 if (is_object($GLOBALS['BE_USER'])) {
881 $GLOBALS['BE_USER']->writelog($type,$action,$error,$details_nr,$details,$data);
882 }
883 }
884 }
885
886 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extfilefunc.php']) {
887 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_extfilefunc.php']);
888 }
889 ?>