|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Contains class with basic file management functions 00029 * 00030 * $Id: class.t3lib_basicfilefunc.php 10493 2011-02-19 10:46:02Z lolli $ 00031 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj 00032 * 00033 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00034 */ 00035 /** 00036 * [CLASS/FUNCTION INDEX of SCRIPT] 00037 * 00038 * 00039 * 00040 * 81: class t3lib_basicFileFunctions 00041 * 00042 * SECTION: Checking functions 00043 * 133: function init($mounts, $f_ext) 00044 * 152: function getTotalFileInfo($wholePath) 00045 * 172: function is_allowed($iconkey,$type) 00046 * 197: function checkIfFullAccess($theDest) 00047 * 211: function is_webpath($path) 00048 * 231: function checkIfAllowed($ext, $theDest, $filename='') 00049 * 241: function checkFileNameLen($fileName) 00050 * 251: function is_directory($theDir) 00051 * 268: function isPathValid($theFile) 00052 * 283: function getUniqueName($theFile, $theDest, $dontCheckForUnique=0) 00053 * 326: function checkPathAgainstMounts($thePath) 00054 * 342: function findFirstWebFolder() 00055 * 362: function blindPath($thePath) 00056 * 378: function findTempFolder() 00057 * 00058 * SECTION: Cleaning functions 00059 * 412: function cleanDirectoryName($theDir) 00060 * 422: function rmDoubleSlash($string) 00061 * 432: function slashPath($path) 00062 * 446: function cleanFileName($fileName,$charset='') 00063 * 480: function formatSize($sizeInBytes) 00064 * 00065 * TOTAL FUNCTIONS: 19 00066 * (This index is automatically created/updated by the extension "extdeveval") 00067 * 00068 */ 00069 00070 00071 /** 00072 * Contains functions for management, validation etc of files in TYPO3, using the concepts of web- and ftp-space. Please see the comment for the init() function 00073 * 00074 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00075 * @package TYPO3 00076 * @subpackage t3lib 00077 * @see t3lib_basicFileFunctions::init() 00078 */ 00079 class t3lib_basicFileFunctions { 00080 var $getUniqueNamePrefix = ''; // Prefix which will be prepended the file when using the getUniqueName-function 00081 var $maxNumber = 99; // This number decides the highest allowed appended number used on a filename before we use naming with unique strings 00082 var $uniquePrecision = 6; // This number decides how many characters out of a unique MD5-hash that is appended to a filename if getUniqueName is asked to find an available filename. 00083 var $maxInputNameLen = 60; // This is the maximum length of names treated by cleanFileName() 00084 var $tempFN = '_temp_'; // Temp-foldername. A folder in the root of one of the mounts with this name is regarded a TEMP-folder (used for upload from clipboard) 00085 00086 // internal 00087 var $f_ext = Array(); // See comment in header 00088 var $mounts = Array(); // See comment in header 00089 var $webPath = ''; // Set to DOCUMENT_ROOT. 00090 var $isInit = 0; // Set to true after init()/start(); 00091 00092 00093 /********************************** 00094 * 00095 * Checking functions 00096 * 00097 **********************************/ 00098 00099 /** 00100 * Constructor 00101 * This function should be called to initialise the internal arrays $this->mounts and $this->f_ext 00102 * 00103 * A typical example of the array $mounts is this: 00104 * $mounts[xx][path] = (..a mounted path..) 00105 * the 'xx'-keys is just numerical from zero. There are also a [name] and [type] value that just denotes the mountname and type. Not used for athentication here. 00106 * $this->mounts is traversed in the function checkPathAgainstMounts($thePath), and it is checked that $thePath is actually below one of the mount-paths 00107 * The mountpaths are with a trailing '/'. $thePath must be with a trailing '/' also! 00108 * As you can see, $this->mounts is very critical! This is the array that decides where the user will be allowed to copy files!! 00109 * Typically the global var $WEBMOUNTS would be passed along as $mounts 00110 * 00111 * A typical example of the array $f_ext is this: 00112 * $f_ext['webspace']['allow']=''; 00113 * $f_ext['webspace']['deny']= PHP_EXTENSIONS_DEFAULT; 00114 * $f_ext['ftpspace']['allow']='*'; 00115 * $f_ext['ftpspace']['deny']=''; 00116 * The control of fileextensions goes in two catagories. Webspace and Ftpspace. Webspace is folders accessible from a webbrowser (below TYPO3_DOCUMENT_ROOT) and ftpspace is everything else. 00117 * The control is done like this: If an extension matches 'allow' then the check returns true. If not and an extension matches 'deny' then the check return false. If no match at all, returns true. 00118 * You list extensions comma-separated. If the value is a '*' every extension is allowed 00119 * The list is case-insensitive when used in this class (see init()) 00120 * Typically TYPO3_CONF_VARS['BE']['fileExtensions'] would be passed along as $f_ext. 00121 * 00122 * Example: 00123 * $basicff->init($GLOBALS['FILEMOUNTS'],$TYPO3_CONF_VARS['BE']['fileExtensions']); 00124 * 00125 * @param array Contains the paths of the file mounts for the current BE user. Normally $GLOBALS['FILEMOUNTS'] is passed. This variable is set during backend user initialization; $FILEMOUNTS = $BE_USER->returnFilemounts(); (see typo3/init.php) 00126 * @param array Array with information about allowed and denied file extensions. Typically passed: $TYPO3_CONF_VARS['BE']['fileExtensions'] 00127 * @return void 00128 * @see typo3/init.php, t3lib_userAuthGroup::returnFilemounts() 00129 */ 00130 function init($mounts, $f_ext) { 00131 $this->f_ext['webspace']['allow'] = t3lib_div::uniqueList(strtolower($f_ext['webspace']['allow'])); 00132 $this->f_ext['webspace']['deny'] = t3lib_div::uniqueList(strtolower($f_ext['webspace']['deny'])); 00133 $this->f_ext['ftpspace']['allow'] = t3lib_div::uniqueList(strtolower($f_ext['ftpspace']['allow'])); 00134 $this->f_ext['ftpspace']['deny'] = t3lib_div::uniqueList(strtolower($f_ext['ftpspace']['deny'])); 00135 00136 $this->mounts = $mounts; 00137 $this->webPath = t3lib_div::getIndpEnv('TYPO3_DOCUMENT_ROOT'); 00138 $this->isInit = 1; 00139 00140 $this->maxInputNameLen = $GLOBALS['TYPO3_CONF_VARS']['SYS']['maxFileNameLength'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['maxFileNameLength'] : $this->maxInputNameLen; 00141 } 00142 00143 /** 00144 * Returns an array with a whole lot of fileinformation. 00145 * Information includes: 00146 * - path : path part of give file 00147 * - file : filename 00148 * - filebody : filename without extension 00149 * - fileext : lowercase extension 00150 * - realFileext : extension 00151 * - tstamp : timestamp of modification 00152 * - size : file size 00153 * - type : file type (block/char/dir/fifo/file/link) 00154 * - owner : user ID of owner of file 00155 * - perms : numerical representation of file permissions 00156 * - writable : is file writeable by web user (FALSE = yes; TRUE = no) *) 00157 * - readable : is file readable by web user (FALSE = yes; TRUE = no) *) 00158 * 00159 * *) logic is reversed because of handling by functions in class.file_list.inc 00160 * 00161 * @param string Filepath to existing file. Should probably be absolute. Filefunctions are performed on this value. 00162 * @return array Information about the file in the filepath 00163 */ 00164 function getTotalFileInfo($wholePath) { 00165 $theuser = getmyuid(); 00166 $info = t3lib_div::split_fileref($wholePath); 00167 $info['tstamp'] = @filemtime($wholePath); 00168 $info['size'] = @filesize($wholePath); 00169 $info['type'] = @filetype($wholePath); 00170 $info['owner'] = @fileowner($wholePath); 00171 $info['perms'] = @fileperms($wholePath); 00172 $info['writable'] = !@is_writable($wholePath); 00173 $info['readable'] = !@is_readable($wholePath); 00174 return $info; 00175 } 00176 00177 /** 00178 * Checks if a $iconkey (fileextension) is allowed according to $this->f_ext. 00179 * 00180 * @param string The extension to check, eg. "php" or "html" etc. 00181 * @param string Either "webspage" or "ftpspace" - points to a key in $this->f_ext 00182 * @return boolean True if file extension is allowed. 00183 */ 00184 function is_allowed($iconkey, $type) { 00185 if (isset($this->f_ext[$type])) { 00186 $ik = strtolower($iconkey); 00187 if ($ik) { 00188 // If the extension is found amongst the allowed types, we return true immediately 00189 if ($this->f_ext[$type]['allow'] == '*' || t3lib_div::inList($this->f_ext[$type]['allow'], $ik)) { 00190 return TRUE; 00191 } 00192 // If the extension is found amongst the denied types, we return false immediately 00193 if ($this->f_ext[$type]['deny'] == '*' || t3lib_div::inList($this->f_ext[$type]['deny'], $ik)) { 00194 return FALSE; 00195 } 00196 // If no match we return true 00197 return TRUE; 00198 } else { // If no extension: 00199 if ($this->f_ext[$type]['allow'] == '*') { 00200 return TRUE; 00201 } 00202 if ($this->f_ext[$type]['deny'] == '*') { 00203 return FALSE; 00204 } 00205 return TRUE; 00206 } 00207 } 00208 return FALSE; 00209 } 00210 00211 /** 00212 * Returns true if you can operate of ANY file ('*') in the space $theDest is in ('webspace' / 'ftpspace') 00213 * 00214 * @param string Absolute path 00215 * @return boolean 00216 */ 00217 function checkIfFullAccess($theDest) { 00218 $type = $this->is_webpath($theDest) ? 'webspace' : 'ftpspace'; 00219 if (isset($this->f_ext[$type])) { 00220 if ((string) $this->f_ext[$type]['deny'] == '' || $this->f_ext[$type]['allow'] == '*') { 00221 return TRUE; 00222 } 00223 } 00224 } 00225 00226 /** 00227 * Checks if $this->webPath (should be TYPO3_DOCUMENT_ROOT) is in the first part of $path 00228 * Returns true also if $this->init is not set or if $path is empty... 00229 * 00230 * @param string Absolute path to check 00231 * @return boolean 00232 */ 00233 function is_webpath($path) { 00234 if ($this->isInit) { 00235 $testPath = $this->slashPath($path); 00236 $testPathWeb = $this->slashPath($this->webPath); 00237 if ($testPathWeb && $testPath) { 00238 return t3lib_div::isFirstPartOfStr($testPath, $testPathWeb); 00239 } 00240 } 00241 return TRUE; // Its more safe to return true (as the webpath is more restricted) if something went wrong... 00242 } 00243 00244 /** 00245 * If the filename is given, check it against the TYPO3_CONF_VARS[BE][fileDenyPattern] + 00246 * Checks if the $ext fileextension is allowed in the path $theDest (this is based on whether $theDest is below the $this->webPath) 00247 * 00248 * @param string File extension, eg. "php" or "html" 00249 * @param string Absolute path for which to test 00250 * @param string Filename to check against TYPO3_CONF_VARS[BE][fileDenyPattern] 00251 * @return boolean True if extension/filename is allowed 00252 */ 00253 function checkIfAllowed($ext, $theDest, $filename = '') { 00254 return t3lib_div::verifyFilenameAgainstDenyPattern($filename) && $this->is_allowed($ext, ($this->is_webpath($theDest) ? 'webspace' : 'ftpspace')); 00255 } 00256 00257 /** 00258 * Returns true if the input filename string is shorter than $this->maxInputNameLen. 00259 * 00260 * @param string Filename, eg "somefile.html" 00261 * @return boolean 00262 */ 00263 function checkFileNameLen($fileName) { 00264 return strlen($fileName) <= $this->maxInputNameLen; 00265 } 00266 00267 /** 00268 * Cleans $theDir for slashes in the end of the string and returns the new path, if it exists on the server. 00269 * 00270 * @param string Directory path to check 00271 * @return string Returns the cleaned up directory name if OK, otherwise false. 00272 */ 00273 function is_directory($theDir) { 00274 if ($this->isPathValid($theDir)) { 00275 $theDir = $this->cleanDirectoryName($theDir); 00276 if (@is_dir($theDir)) { 00277 return $theDir; 00278 } 00279 } 00280 return FALSE; 00281 } 00282 00283 /** 00284 * Wrapper for t3lib_div::validPathStr() 00285 * 00286 * @param string Filepath to evaluate 00287 * @return boolean True, if no '//', '..' or '\' is in the $theFile 00288 * @see t3lib_div::validPathStr() 00289 */ 00290 function isPathValid($theFile) { 00291 return t3lib_div::validPathStr($theFile); 00292 } 00293 00294 /** 00295 * Returns the destination path/filename of a unique filename/foldername in that path. 00296 * If $theFile exists in $theDest (directory) the file have numbers appended up to $this->maxNumber. Hereafter a unique string will be appended. 00297 * This function is used by fx. TCEmain when files are attached to records and needs to be uniquely named in the uploads/* folders 00298 * 00299 * @param string The input filename to check 00300 * @param string The directory for which to return a unique filename for $theFile. $theDest MUST be a valid directory. Should be absolute. 00301 * @param boolean If set the filename is returned with the path prepended without checking whether it already existed! 00302 * @return string The destination absolute filepath (not just the name!) of a unique filename/foldername in that path. 00303 * @see t3lib_TCEmain::checkValue() 00304 */ 00305 function getUniqueName($theFile, $theDest, $dontCheckForUnique = 0) { 00306 $theDest = $this->is_directory($theDest); // $theDest is cleaned up 00307 $origFileInfo = t3lib_div::split_fileref($theFile); // Fetches info about path, name, extention of $theFile 00308 if ($theDest) { 00309 if ($this->getUniqueNamePrefix) { // Adds prefix 00310 $origFileInfo['file'] = $this->getUniqueNamePrefix . $origFileInfo['file']; 00311 $origFileInfo['filebody'] = $this->getUniqueNamePrefix . $origFileInfo['filebody']; 00312 } 00313 00314 // Check if the file exists and if not - return the filename... 00315 $fileInfo = $origFileInfo; 00316 $theDestFile = $theDest . '/' . $fileInfo['file']; // The destinations file 00317 if (!file_exists($theDestFile) || $dontCheckForUnique) { // If the file does NOT exist we return this filename 00318 return $theDestFile; 00319 } 00320 00321 // Well the filename in its pure form existed. Now we try to append numbers / unique-strings and see if we can find an available filename... 00322 $theTempFileBody = preg_replace('/_[0-9][0-9]$/', '', $origFileInfo['filebody']); // This removes _xx if appended to the file 00323 $theOrigExt = $origFileInfo['realFileext'] ? '.' . $origFileInfo['realFileext'] : ''; 00324 00325 for ($a = 1; $a <= ($this->maxNumber + 1); $a++) { 00326 if ($a <= $this->maxNumber) { // First we try to append numbers 00327 $insert = '_' . sprintf('%02d', $a); 00328 } else { // .. then we try unique-strings... 00329 $insert = '_' . substr(md5(uniqId('')), 0, $this->uniquePrecision); 00330 } 00331 $theTestFile = $theTempFileBody . $insert . $theOrigExt; 00332 $theDestFile = $theDest . '/' . $theTestFile; // The destinations file 00333 if (!file_exists($theDestFile)) { // If the file does NOT exist we return this filename 00334 return $theDestFile; 00335 } 00336 } 00337 } 00338 } 00339 00340 /** 00341 * Checks if $thePath is a path under one of the paths in $this->mounts 00342 * See comment in the header of this class. 00343 * 00344 * @param string $thePath MUST HAVE a trailing '/' in order to match correctly with the mounts 00345 * @return string The key to the first mount found, otherwise nothing is returned. 00346 * @see init() 00347 */ 00348 function checkPathAgainstMounts($thePath) { 00349 if ($thePath && $this->isPathValid($thePath) && is_array($this->mounts)) { 00350 foreach ($this->mounts as $k => $val) { 00351 if (t3lib_div::isFirstPartOfStr($thePath, $val['path'])) { 00352 return $k; 00353 } 00354 } 00355 } 00356 } 00357 00358 /** 00359 * Find first web folder (relative to PATH_site.'fileadmin') in filemounts array 00360 * 00361 * @return string The key to the first mount inside PATH_site."fileadmin" found, otherwise nothing is returned. 00362 */ 00363 function findFirstWebFolder() { 00364 global $TYPO3_CONF_VARS; 00365 00366 if (is_array($this->mounts)) { 00367 foreach ($this->mounts as $k => $val) { 00368 if (t3lib_div::isFirstPartOfStr($val['path'], PATH_site . $TYPO3_CONF_VARS['BE']['fileadminDir'])) { 00369 return $k; 00370 } 00371 } 00372 } 00373 } 00374 00375 /** 00376 * Removes filemount part of a path, thus blinding the position. 00377 * Takes a path, $thePath, and removes the part of the path which equals the filemount. 00378 * 00379 * @param string $thePath is a path which MUST be found within one of the internally set filemounts, $this->mounts 00380 * @return string The processed input path 00381 */ 00382 function blindPath($thePath) { 00383 $k = $this->checkPathAgainstMounts($thePath); 00384 if ($k) { 00385 $name = ''; 00386 $name .= '[' . $this->mounts[$k]['name'] . ']: '; 00387 $name .= substr($thePath, strlen($this->mounts[$k]['path'])); 00388 return $name; 00389 } 00390 } 00391 00392 /** 00393 * Find temporary folder 00394 * Finds the first $this->tempFN ('_temp_' usually) -folder in the internal array of filemounts, $this->mounts 00395 * 00396 * @return string Returns the path if found, otherwise nothing if error. 00397 */ 00398 function findTempFolder() { 00399 if ($this->tempFN && is_array($this->mounts)) { 00400 foreach ($this->mounts as $k => $val) { 00401 $tDir = $val['path'] . $this->tempFN; 00402 if (@is_dir($tDir)) { 00403 return $tDir; 00404 } 00405 } 00406 } 00407 } 00408 00409 00410 /********************* 00411 * 00412 * Cleaning functions 00413 * 00414 *********************/ 00415 00416 /** 00417 * Removes all dots, slashes and spaces after a path... 00418 * 00419 * @param string Input string 00420 * @return string Output string 00421 */ 00422 function cleanDirectoryName($theDir) { 00423 return preg_replace('/[\/\. ]*$/', '', $this->rmDoubleSlash($theDir)); 00424 } 00425 00426 /** 00427 * Converts any double slashes (//) to a single slash (/) 00428 * 00429 * @param string Input value 00430 * @return string Returns the converted string 00431 */ 00432 function rmDoubleSlash($string) { 00433 return str_replace('//', '/', $string); 00434 } 00435 00436 /** 00437 * Returns a string which has a slash '/' appended if it doesn't already have that slash 00438 * 00439 * @param string Input string 00440 * @return string Output string with a slash in the end (if not already there) 00441 */ 00442 function slashPath($path) { 00443 if (substr($path, -1) != '/') { 00444 return $path . '/'; 00445 } 00446 return $path; 00447 } 00448 00449 /** 00450 * Returns a string where any character not matching [.a-zA-Z0-9_-] is substituted by '_' 00451 * Trailing dots are removed 00452 * 00453 * @param string Input string, typically the body of a filename 00454 * @param string Charset of the a filename (defaults to current charset; depending on context) 00455 * @return string Output string with any characters not matching [.a-zA-Z0-9_-] is substituted by '_' and trailing dots removed 00456 */ 00457 function cleanFileName($fileName, $charset = '') { 00458 // Handle UTF-8 characters 00459 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] == 'utf-8' && $GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) { 00460 // allow ".", "-", 0-9, a-z, A-Z and everything beyond U+C0 (latin capital letter a with grave) 00461 $cleanFileName = preg_replace('/[\x00-\x2C\/\x3A-\x3F\x5B-\x60\x7B-\xBF]/u', '_', trim($fileName)); 00462 00463 // Handle other character sets 00464 } else { 00465 // Get conversion object or initialize if needed 00466 if (!is_object($this->csConvObj)) { 00467 if (TYPO3_MODE == 'FE') { 00468 $this->csConvObj = $GLOBALS['TSFE']->csConvObj; 00469 } elseif (is_object($GLOBALS['LANG'])) { // BE assumed: 00470 $this->csConvObj = $GLOBALS['LANG']->csConvObj; 00471 } else { // The object may not exist yet, so we need to create it now. Happens in the Install Tool for example. 00472 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs'); 00473 } 00474 } 00475 00476 // Define character set 00477 if (!$charset) { 00478 if (TYPO3_MODE == 'FE') { 00479 $charset = $GLOBALS['TSFE']->renderCharset; 00480 } elseif (is_object($GLOBALS['LANG'])) { // BE assumed: 00481 $charset = $GLOBALS['LANG']->charSet; 00482 } else { // best guess 00483 $charset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']; 00484 } 00485 } 00486 00487 // If a charset was found, convert filename 00488 if ($charset) { 00489 $fileName = $this->csConvObj->specCharsToASCII($charset, $fileName); 00490 } 00491 00492 // Replace unwanted characters by underscores 00493 $cleanFileName = preg_replace('/[^.[:alnum:]_-]/', '_', trim($fileName)); 00494 } 00495 // Strip trailing dots and return 00496 return preg_replace('/\.*$/', '', $cleanFileName); 00497 } 00498 } 00499 00500 00501 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_basicfilefunc.php'])) { 00502 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_basicfilefunc.php']); 00503 } 00504 00505 ?>
1.8.0