TYPO3 CMS  TYPO3_6-2
LocalDriver.php
Go to the documentation of this file.
1 <?php
3 
20 
26 
30  const UNSAFE_FILENAME_CHARACTER_EXPRESSION = '\\x00-\\x2C\\/\\x3A-\\x3F\\x5B-\\x60\\x7B-\\xBF';
31 
37  protected $absoluteBasePath;
38 
44  protected $supportedHashAlgorithms = array('sha1', 'md5');
45 
52  protected $baseUri = NULL;
53 
57  protected $charsetConversion;
58 
60  protected $mappingFolderNameToRole = array(
61  '_recycler_' => FolderInterface::ROLE_RECYCLER,
63  'user_upload' => FolderInterface::ROLE_USERUPLOAD,
64  );
65 
69  public function __construct(array $configuration = array()) {
70  parent::__construct($configuration);
71  // The capabilities default of this driver. See CAPABILITY_* constants for possible values
72  $this->capabilities =
76  }
77 
88  $this->capabilities &= $capabilities;
89  return $this->capabilities;
90  }
91 
92 
98  public function processConfiguration() {
99  $this->absoluteBasePath = $this->calculateBasePath($this->configuration);
100  $this->determineBaseUrl();
101  if ($this->baseUri === NULL) {
102  // remove public flag
104  }
105  }
106 
113  public function initialize() {
114  }
115 
122  protected function determineBaseUrl() {
123  // only calculate baseURI if the storage does not enforce jumpUrl Script
124  if ($this->hasCapability(\TYPO3\CMS\Core\Resource\ResourceStorage::CAPABILITY_PUBLIC)) {
125  if (GeneralUtility::isFirstPartOfStr($this->absoluteBasePath, PATH_site)) {
126  // use site-relative URLs
127  $temporaryBaseUri = rtrim(\TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($this->absoluteBasePath), '/');
128  if ($temporaryBaseUri !== '') {
129  $uriParts = explode('/', $temporaryBaseUri);
130  $uriParts = array_map('rawurlencode', $uriParts);
131  $temporaryBaseUri = implode('/', $uriParts) . '/';
132  }
133  $this->baseUri = $temporaryBaseUri;
134  } elseif (isset($this->configuration['baseUri']) && GeneralUtility::isValidUrl($this->configuration['baseUri'])) {
135  $this->baseUri = rtrim($this->configuration['baseUri'], '/') . '/';
136  }
137  }
138  }
139 
147  protected function calculateBasePath(array $configuration) {
148  if (!array_key_exists('basePath', $configuration) || empty($configuration['basePath'])) {
149  throw new \TYPO3\CMS\Core\Resource\Exception\InvalidConfigurationException(
150  'Configuration must contain base path.',
151  1346510477
152  );
153  }
154 
155  if ($configuration['pathType'] === 'relative') {
156  $relativeBasePath = $configuration['basePath'];
157  $absoluteBasePath = PATH_site . $relativeBasePath;
158  } else {
159  $absoluteBasePath = $configuration['basePath'];
160  }
162  $absoluteBasePath = rtrim($absoluteBasePath, '/') . '/';
163  if (!is_dir($absoluteBasePath)) {
164  throw new \TYPO3\CMS\Core\Resource\Exception\InvalidConfigurationException(
165  'Base path "' . $absoluteBasePath . '" does not exist or is no directory.',
166  1299233097
167  );
168  }
169  return $absoluteBasePath;
170  }
171 
180  public function getPublicUrl($identifier) {
181  $publicUrl = NULL;
182  if ($this->baseUri !== NULL) {
183  $uriParts = explode('/', ltrim($identifier, '/'));
184  $uriParts = array_map('rawurlencode', $uriParts);
185  $identifier = implode('/', $uriParts);
186  $publicUrl = $this->baseUri . $identifier;
187  }
188  return $publicUrl;
189  }
190 
196  public function getRootLevelFolder() {
197  return '/';
198  }
199 
205  public function getDefaultFolder() {
206  $identifier = '/user_upload/';
207  $createFolder = !$this->folderExists($identifier);
208  if ($createFolder === TRUE) {
209  $identifier = $this->createFolder('user_upload');
210  }
211  return $identifier;
212  }
213 
223  public function createFolder($newFolderName, $parentFolderIdentifier = '', $recursive = FALSE) {
224  $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
225  $newFolderName = trim($newFolderName, '/');
226  if ($recursive == FALSE) {
227  $newFolderName = $this->sanitizeFileName($newFolderName);
228  $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
229  GeneralUtility::mkdir($this->getAbsolutePath($newIdentifier));
230  } else {
231  $parts = GeneralUtility::trimExplode('/', $newFolderName);
232  $parts = array_map(array($this, 'sanitizeFileName'), $parts);
233  $newFolderName = implode('/', $parts);
234  $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
235  GeneralUtility::mkdir_deep($this->getAbsolutePath($parentFolderIdentifier) . '/', $newFolderName);
236  }
237  return $newIdentifier;
238  }
239 
248  public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = array()) {
249  $dirPath = PathUtility::dirname($fileIdentifier);
250  $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath);
251 
252  $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
253  // don't use $this->fileExists() because we need the absolute path to the file anyways, so we can directly
254  // use PHP's filesystem method.
255  if (!file_exists($absoluteFilePath) || !is_file($absoluteFilePath)) {
256  throw new \InvalidArgumentException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
257  }
258  return $this->extractFileInformation($absoluteFilePath, $dirPath, $propertiesToExtract);
259  }
260 
268  public function getFolderInfoByIdentifier($folderIdentifier) {
269  $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
270 
271  if (!$this->folderExists($folderIdentifier)) {
272  throw new \TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException(
273  'File ' . $folderIdentifier . ' does not exist.',
274  1314516810
275  );
276  }
277  return array(
278  'identifier' => $folderIdentifier,
279  'name' => PathUtility::basename($folderIdentifier),
280  'storage' => $this->storageUid
281  );
282  }
283 
296  public function sanitizeFileName($fileName, $charset = '') {
297  // Handle UTF-8 characters
298  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
299  // Allow ".", "-", 0-9, a-z, A-Z and everything beyond U+C0 (latin capital letter a with grave)
300  $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . ']/u', '_', trim($fileName));
301  } else {
302  // Define character set
303  if (!$charset) {
304  if (TYPO3_MODE === 'FE') {
305  $charset = $GLOBALS['TSFE']->renderCharset;
306  } else {
307  // default for Backend
308  $charset = 'utf-8';
309  }
310  }
311  // If a charset was found, convert fileName
312  if ($charset) {
313  $fileName = $this->getCharsetConversion()->specCharsToASCII($charset, $fileName);
314  }
315  // Replace unwanted characters by underscores
316  $cleanFileName = preg_replace('/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION . '\\xC0-\\xFF]/', '_', trim($fileName));
317  }
318  // Strip trailing dots and return
319  $cleanFileName = rtrim($cleanFileName, '.');
320  if ($cleanFileName === '') {
321  throw new \TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException(
322  'File name ' . $fileName . ' is invalid.',
323  1320288991
324  );
325  }
326  return $cleanFileName;
327  }
328 
343  protected function getDirectoryItemList($folderIdentifier, $start = 0, $numberOfItems = 0, array $filterMethods, $includeFiles = TRUE, $includeDirs = TRUE, $recursive = FALSE) {
344  $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
345  $realPath = $this->getAbsolutePath($folderIdentifier);
346  if (!is_dir($realPath)) {
347  throw new \InvalidArgumentException(
348  'Cannot list items in directory ' . $folderIdentifier . ' - does not exist or is no directory',
349  1314349666
350  );
351  }
352 
353  // Fetch the files and folders and sort them by name; we have to do
354  // this here because the directory iterator does return them in
355  // an arbitrary order
356  $items = $this->retrieveFileAndFoldersInPath($realPath, $recursive, $includeFiles, $includeDirs);
357  uksort(
358  $items,
359  array('\\TYPO3\\CMS\\Core\\Utility\\ResourceUtility', 'recursiveFileListSortingHelper')
360  );
361 
362  $iterator = new \ArrayIterator($items);
363  if ($iterator->count() === 0) {
364  return array();
365  }
366 
367  // $c is the counter for how many items we still have to fetch (-1 is unlimited)
368  $c = $numberOfItems > 0 ? $numberOfItems : - 1;
369  $items = array();
370  while ($iterator->valid() && ($numberOfItems === 0 || $c > 0)) {
371  // $iteratorItem is the file or folder name
372  $iteratorItem = $iterator->current();
373  // go on to the next iterator item now as we might skip this one early
374  $iterator->next();
375 
376  if (
378  $filterMethods,
379  $iteratorItem['name'],
380  $iteratorItem['identifier'],
381  $this->getParentFolderIdentifierOfIdentifier($iteratorItem['identifier'])
382  )
383  ) {
384  continue;
385  }
386 
387  if ($start > 0) {
388  $start--;
389  } else {
390  $items[$iteratorItem['identifier']] = $iteratorItem['identifier'];
391  // Decrement item counter to make sure we only return $numberOfItems
392  // we cannot do this earlier in the method (unlike moving the iterator forward) because we only add the
393  // item here
394  --$c;
395  }
396  }
397  return $items;
398  }
399 
411  protected function applyFilterMethodsToDirectoryItem(array $filterMethods, $itemName, $itemIdentifier, $parentIdentifier) {
412  foreach ($filterMethods as $filter) {
413  if (is_callable($filter)) {
414  $result = call_user_func($filter, $itemName, $itemIdentifier, $parentIdentifier, array(), $this);
415  // We have to use -1 as the „don't include“ return value, as call_user_func() will return FALSE
416  // If calling the method succeeded and thus we can't use that as a return value.
417  if ($result === -1) {
418  return FALSE;
419  } elseif ($result === FALSE) {
420  throw new \RuntimeException('Could not apply file/folder name filter ' . $filter[0] . '::' . $filter[1]);
421  }
422  }
423  }
424  return TRUE;
425  }
426 
438  public function getFilesInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive = FALSE, array $filenameFilterCallbacks = array()) {
439  return $this->getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $filenameFilterCallbacks, TRUE, FALSE, $recursive);
440  }
441 
453  public function getFoldersInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive = FALSE, array $folderNameFilterCallbacks = array()) {
454  return $this->getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $folderNameFilterCallbacks, FALSE, TRUE, $recursive);
455  }
456 
466  protected function retrieveFileAndFoldersInPath($path, $recursive = FALSE, $includeFiles = TRUE, $includeDirs = TRUE) {
467  $pathLength = strlen($this->getAbsoluteBasePath());
468  $iteratorMode = \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::FOLLOW_SYMLINKS;
469  if ($recursive) {
470  $iterator = new \RecursiveIteratorIterator(
471  new \RecursiveDirectoryIterator($path, $iteratorMode),
472  \RecursiveIteratorIterator::SELF_FIRST
473  );
474  } else {
475  $iterator = new \RecursiveDirectoryIterator($path, $iteratorMode);
476  }
477 
478  $directoryEntries = array();
479  while ($iterator->valid()) {
481  $entry = $iterator->current();
482  // skip non-files/non-folders, and empty entries
483  if ((!$entry->isFile() && !$entry->isDir()) || $entry->getFilename() == '' ||
484  ($entry->isFile() && !$includeFiles) || ($entry->isDir() && !$includeDirs)) {
485  $iterator->next();
486  continue;
487  }
488  $entryIdentifier = '/' . substr($entry->getPathname(), $pathLength);
489  $entryName = PathUtility::basename($entryIdentifier);
490  if ($entry->isDir()) {
491  $entryIdentifier .= '/';
492  }
493  $entryArray = array(
494  'identifier' => $entryIdentifier,
495  'name' => $entryName,
496  'type' => $entry->isDir() ? 'dir' : 'file'
497  );
498  $directoryEntries[$entryIdentifier] = $entryArray;
499  $iterator->next();
500  }
501  return $directoryEntries;
502  }
503 
512  protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = array()) {
513  if (count($propertiesToExtract) === 0) {
514  $propertiesToExtract = array(
515  'size', 'atime', 'atime', 'mtime', 'ctime', 'mimetype', 'name',
516  'identifier', 'identifier_hash', 'storage', 'folder_hash'
517  );
518  }
519  $fileInformation = array();
520  foreach ($propertiesToExtract as $property) {
521  $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
522  }
523  return $fileInformation;
524  }
525 
526 
537  public function getSpecificFileInformation($fileIdentifier, $containerPath, $property) {
538  $identifier = $this->canonicalizeAndCheckFileIdentifier($containerPath . PathUtility::basename($fileIdentifier));
539 
540  switch ($property) {
541  case 'size':
542  return filesize($fileIdentifier);
543  case 'atime':
544  return fileatime($fileIdentifier);
545  case 'mtime':
546  return filemtime($fileIdentifier);
547  case 'ctime':
548  return filectime($fileIdentifier);
549  case 'name':
550  return PathUtility::basename($fileIdentifier);
551  case 'mimetype':
552  return $this->getMimeTypeOfFile($fileIdentifier);
553  case 'identifier':
554  return $identifier;
555  case 'storage':
556  return $this->storageUid;
557  case 'identifier_hash':
558  return $this->hashIdentifier($identifier);
559  case 'folder_hash':
560  return $this->hashIdentifier($this->getParentFolderIdentifierOfIdentifier($identifier));
561  default:
562  throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
563  }
564  return NULL;
565  }
566 
572  protected function getAbsoluteBasePath() {
574  }
575 
583  protected function getAbsolutePath($fileIdentifier) {
584  $relativeFilePath = ltrim($this->canonicalizeAndCheckFileIdentifier($fileIdentifier), '/');
585  $path = $this->absoluteBasePath . $relativeFilePath;
586  return $path;
587  }
588 
595  protected function getMimeTypeOfFile($absoluteFilePath) {
596  if (function_exists('finfo_file')) {
597  $fileInfo = new \finfo();
598  return $fileInfo->file($absoluteFilePath, FILEINFO_MIME_TYPE);
599  } elseif (function_exists('mime_content_type')) {
600  return mime_content_type($absoluteFilePath);
601  }
602  return FALSE;
603  }
604 
614  public function hash($fileIdentifier, $hashAlgorithm) {
615  if (!in_array($hashAlgorithm, $this->supportedHashAlgorithms)) {
616  throw new \InvalidArgumentException('Hash algorithm "' . $hashAlgorithm . '" is not supported.', 1304964032);
617  }
618  switch ($hashAlgorithm) {
619  case 'sha1':
620  $hash = sha1_file($this->getAbsolutePath($fileIdentifier));
621  break;
622  case 'md5':
623  $hash = md5_file($this->getAbsolutePath($fileIdentifier));
624  break;
625  default:
626  throw new \RuntimeException('Hash algorithm ' . $hashAlgorithm . ' is not implemented.', 1329644451);
627  }
628  return $hash;
629  }
630 
644  public function addFile($localFilePath, $targetFolderIdentifier, $newFileName = '', $removeOriginal = TRUE) {
645  $localFilePath = $this->canonicalizeAndCheckFilePath($localFilePath);
646  // as for the "virtual storage" for backwards-compatibility, this check always fails, as the file probably lies under PATH_site
647  // thus, it is not checked here
648  // @ todo is check in storage
649  if (GeneralUtility::isFirstPartOfStr($localFilePath, $this->absoluteBasePath) && $this->storageUid > 0) {
650  throw new \InvalidArgumentException('Cannot add a file that is already part of this storage.', 1314778269);
651  }
652  $newFileName = $this->sanitizeFileName($newFileName !== '' ? $newFileName : PathUtility::basename($localFilePath));
653  $newFileIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier) . $newFileName;
654  $targetPath = $this->getAbsolutePath($newFileIdentifier);
655 
656  if ($removeOriginal) {
657  if (is_uploaded_file($localFilePath)) {
658  $result = move_uploaded_file($localFilePath, $targetPath);
659  } else {
660  $result = rename($localFilePath, $targetPath);
661  }
662  } else {
663  $result = copy($localFilePath, $targetPath);
664  }
665  if ($result === FALSE || !file_exists($targetPath)) {
666  throw new \RuntimeException('Adding file ' . $localFilePath . ' at ' . $newFileIdentifier . ' failed.');
667  }
668  clearstatcache();
669  // Change the permissions of the file
670  GeneralUtility::fixPermissions($targetPath);
671  return $newFileIdentifier;
672  }
673 
681  public function fileExists($fileIdentifier) {
682  $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
683  return is_file($absoluteFilePath);
684  }
685 
693  public function fileExistsInFolder($fileName, $folderIdentifier) {
694  $identifier = $folderIdentifier . '/' . $fileName;
695  $identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
696  return $this->fileExists($identifier);
697  }
698 
706  public function folderExists($folderIdentifier) {
707  $absoluteFilePath = $this->getAbsolutePath($folderIdentifier);
708  return is_dir($absoluteFilePath);
709  }
710 
718  public function folderExistsInFolder($folderName, $folderIdentifier) {
719  $identifier = $folderIdentifier . '/' . $folderName;
720  $identifier = $this->canonicalizeAndCheckFolderIdentifier($identifier);
721  return $this->folderExists($identifier);
722  }
723 
732  public function getFolderInFolder($folderName, $folderIdentifier) {
733  $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier . '/' . $folderName);
734  return $folderIdentifier;
735  }
736 
745  public function replaceFile($fileIdentifier, $localFilePath) {
746  $filePath = $this->getAbsolutePath($fileIdentifier);
747  $result = rename($localFilePath, $filePath);
749  if ($result === FALSE) {
750  throw new \RuntimeException('Replacing file ' . $fileIdentifier . ' with ' . $localFilePath . ' failed.', 1315314711);
751  }
752  return $result;
753  }
754 
765  public function copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName) {
766  $sourcePath = $this->getAbsolutePath($fileIdentifier);
767  $newIdentifier = $targetFolderIdentifier . '/' . $fileName;
768  $newIdentifier = $this->canonicalizeAndCheckFileIdentifier($newIdentifier);
769 
770  $absoluteFilePath = $this->getAbsolutePath($newIdentifier);
771  copy($sourcePath, $absoluteFilePath);
772  GeneralUtility::fixPermissions($absoluteFilePath);
773  return $newIdentifier;
774  }
775 
788  public function moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName) {
789  $sourcePath = $this->getAbsolutePath($fileIdentifier);
790  $targetIdentifier = $targetFolderIdentifier . '/' . $newFileName;
791  $targetIdentifier = $this->canonicalizeAndCheckFileIdentifier($targetIdentifier);
792  $result = rename($sourcePath, $this->getAbsolutePath($targetIdentifier));
793  if ($result === FALSE) {
794  throw new \RuntimeException('Moving file ' . $sourcePath . ' to ' . $targetIdentifier . ' failed.', 1315314712);
795  }
796  return $targetIdentifier;
797  }
798 
806  protected function copyFileToTemporaryPath($fileIdentifier) {
807  $sourcePath = $this->getAbsolutePath($fileIdentifier);
808  $temporaryPath = $this->getTemporaryPathForFile($fileIdentifier);
809  $result = copy($sourcePath, $temporaryPath);
810  touch($temporaryPath, filemtime($sourcePath));
811  if ($result === FALSE) {
812  throw new \RuntimeException('Copying file ' . $fileIdentifier . ' to temporary path failed.', 1320577649);
813  }
814  return $temporaryPath;
815  }
816 
828  protected function createIdentifierMap(array $filesAndFolders, $sourceFolderIdentifier, $targetFolderIdentifier) {
829  $identifierMap = array();
830  $identifierMap[$sourceFolderIdentifier] = $targetFolderIdentifier;
831  foreach ($filesAndFolders as $oldItem) {
832  if ($oldItem['type'] == 'dir') {
833  $oldIdentifier = $oldItem['identifier'];
834  $newIdentifier = $this->canonicalizeAndCheckFolderIdentifier(
835  str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem['identifier'])
836  );
837  } else {
838  $oldIdentifier = $oldItem['identifier'];
839  $newIdentifier = $this->canonicalizeAndCheckFileIdentifier(
840  str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem['identifier'])
841  );
842  }
843  if (!file_exists($this->getAbsolutePath($newIdentifier))) {
844  throw new \TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException(
845  sprintf('File "%1$s" was not found (should have been copied/moved from "%2$s").', $newIdentifier, $oldIdentifier),
846  1330119453
847  );
848  }
849  $identifierMap[$oldIdentifier] = $newIdentifier;
850  }
851  return $identifierMap;
852  }
853 
864  public function moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName) {
865  $sourcePath = $this->getAbsolutePath($sourceFolderIdentifier);
866  $relativeTargetPath = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier . '/' . $newFolderName);
867  $targetPath = $this->getAbsolutePath($relativeTargetPath);
868  // get all files and folders we are going to move, to have a map for updating later.
869  $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath, TRUE);
870  $result = rename($sourcePath, $targetPath);
871  if ($result === FALSE) {
872  throw new \RuntimeException('Moving folder ' . $sourcePath . ' to ' . $targetPath . ' failed.', 1320711817);
873  }
874  // Create a mapping from old to new identifiers
875  $identifierMap = $this->createIdentifierMap($filesAndFolders, $sourceFolderIdentifier, $relativeTargetPath);
876  return $identifierMap;
877  }
878 
889  public function copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName) {
890  // This target folder path already includes the topmost level, i.e. the folder this method knows as $folderToCopy.
891  // We can thus rely on this folder being present and just create the subfolder we want to copy to.
892  $newFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier . '/' . $newFolderName);
893  $sourceFolderPath = $this->getAbsolutePath($sourceFolderIdentifier);
894  $targetFolderPath = $this->getAbsolutePath($newFolderIdentifier);
895 
896  mkdir($targetFolderPath);
898  $iterator = new \RecursiveIteratorIterator(
899  new \RecursiveDirectoryIterator($sourceFolderPath),
900  \RecursiveIteratorIterator::SELF_FIRST
901  );
902  // Rewind the iterator as this is important for some systems e.g. Windows
903  $iterator->rewind();
904  while ($iterator->valid()) {
906  $current = $iterator->current();
907  $fileName = $current->getFilename();
908  $itemSubPath = GeneralUtility::fixWindowsFilePath($iterator->getSubPathname());
909  if ($current->isDir() && !($fileName === '..' || $fileName === '.')) {
910  GeneralUtility::mkdir($targetFolderPath . '/' . $itemSubPath);
911  } elseif ($current->isFile()) {
912  $result = copy($sourceFolderPath . '/' . $itemSubPath, $targetFolderPath . '/' . $itemSubPath);
913  if ($result === FALSE) {
914  // rollback
915  GeneralUtility::rmdir($targetFolderIdentifier, TRUE);
916  throw new \TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException(
917  'Copying file "' . $sourceFolderPath . $itemSubPath . '" to "' . $targetFolderPath . $itemSubPath . '" failed.',
918  1330119452
919  );
920 
921  }
922  }
923  $iterator->next();
924  }
925  GeneralUtility::fixPermissions($targetFolderPath, TRUE);
926  return TRUE;
927  }
928 
938  public function renameFile($fileIdentifier, $newName) {
939  // Makes sure the Path given as parameter is valid
940  $newName = $this->sanitizeFileName($newName);
941  $newIdentifier = rtrim(GeneralUtility::fixWindowsFilePath(PathUtility::dirname($fileIdentifier)), '/') . '/' . $newName;
942  $newIdentifier = $this->canonicalizeAndCheckFileIdentifier($newIdentifier);
943  // The target should not exist already
944  if ($this->fileExists($newIdentifier)) {
945  throw new \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException('The target file already exists.', 1320291063);
946  }
947  $sourcePath = $this->getAbsolutePath($fileIdentifier);
948  $targetPath = $this->getAbsolutePath($newIdentifier);
949  $result = rename($sourcePath, $targetPath);
950  if ($result === FALSE) {
951  throw new \RuntimeException('Renaming file ' . $sourcePath . ' to ' . $targetPath . ' failed.', 1320375115);
952  }
953  return $newIdentifier;
954  }
955 
956 
965  public function renameFolder($folderIdentifier, $newName) {
966  $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
967  $newName = $this->sanitizeFileName($newName);
968 
969  $newIdentifier = PathUtility::dirname($folderIdentifier) . '/' . $newName;
970  $newIdentifier = $this->canonicalizeAndCheckFolderIdentifier($newIdentifier);
971 
972  $sourcePath = $this->getAbsolutePath($folderIdentifier);
973  $targetPath = $this->getAbsolutePath($newIdentifier);
974  // get all files and folders we are going to move, to have a map for updating later.
975  $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath, TRUE);
976  $result = rename($sourcePath, $targetPath);
977  if ($result === FALSE) {
978  throw new \RuntimeException(sprintf('Renaming folder "%1$s" to "%2$s" failed."', $sourcePath, $targetPath), 1320375116);
979  }
980  try {
981  // Create a mapping from old to new identifiers
982  $identifierMap = $this->createIdentifierMap($filesAndFolders, $folderIdentifier, $newIdentifier);
983  } catch (\Exception $e) {
984  rename($targetPath, $sourcePath);
985  throw new \RuntimeException(
986  sprintf(
987  'Creating filename mapping after renaming "%1$s" to "%2$s" failed. Reverted rename operation.\\n\\nOriginal error: %3$s"',
988  $sourcePath, $targetPath, $e->getMessage()
989  ),
990  1334160746
991  );
992  }
993  return $identifierMap;
994  }
995 
1005  public function deleteFile($fileIdentifier) {
1006  $filePath = $this->getAbsolutePath($fileIdentifier);
1007  $result = unlink($filePath);
1008  if ($result === FALSE) {
1009  throw new \RuntimeException('Deletion of file ' . $fileIdentifier . ' failed.', 1320855304);
1010  }
1011  return $result;
1012  }
1013 
1023  public function deleteFolder($folderIdentifier, $deleteRecursively = FALSE) {
1024  $folderPath = $this->getAbsolutePath($folderIdentifier);
1025  $result = GeneralUtility::rmdir($folderPath, $deleteRecursively);
1026  if ($result === FALSE) {
1027  throw new \TYPO3\CMS\Core\Resource\Exception\FileOperationErrorException(
1028  'Deleting folder "' . $folderIdentifier . '" failed.',
1029  1330119451
1030  );
1031  }
1032  return $result;
1033  }
1034 
1041  public function isFolderEmpty($folderIdentifier) {
1042  $path = $this->getAbsolutePath($folderIdentifier);
1043  $dirHandle = opendir($path);
1044  while ($entry = readdir($dirHandle)) {
1045  if ($entry !== '.' && $entry !== '..') {
1046  closedir($dirHandle);
1047  return FALSE;
1048  }
1049  }
1050  closedir($dirHandle);
1051  return TRUE;
1052  }
1053 
1064  public function getFileForLocalProcessing($fileIdentifier, $writable = TRUE) {
1065  if ($writable === FALSE) {
1066  return $this->getAbsolutePath($fileIdentifier);
1067  } else {
1068  return $this->copyFileToTemporaryPath($fileIdentifier);
1069  }
1070  }
1071 
1072 
1080  public function getPermissions($identifier) {
1081  $path = $this->getAbsolutePath($identifier);
1082  $permissionBits = fileperms($path);
1083  if ($permissionBits === FALSE) {
1084  throw new \TYPO3\CMS\Core\Resource\Exception\ResourcePermissionsUnavailableException(
1085  'Error while fetching permissions for ' . $path,
1086  1319455097
1087  );
1088  }
1089  return array(
1090  'r' => (bool)is_readable($path),
1091  'w' => (bool)is_writable($path)
1092  );
1093  }
1094 
1104  public function isWithin($folderIdentifier, $identifier) {
1105  $folderIdentifier = $this->canonicalizeAndCheckFileIdentifier($folderIdentifier);
1106  $entryIdentifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
1107  if ($folderIdentifier === $entryIdentifier) {
1108  return TRUE;
1109  }
1110  // File identifier canonicalization will not modify a single slash so
1111  // we must not append another slash in that case.
1112  if ($folderIdentifier !== '/') {
1113  $folderIdentifier .= '/';
1114  }
1115  return GeneralUtility::isFirstPartOfStr($entryIdentifier, $folderIdentifier);
1116  }
1117 
1127  public function createFile($fileName, $parentFolderIdentifier) {
1128  if (!$this->isValidFilename($fileName)) {
1129  throw new \TYPO3\CMS\Core\Resource\Exception\InvalidFileNameException(
1130  'Invalid characters in fileName "' . $fileName . '"',
1131  1320572272
1132  );
1133  }
1134  $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
1135  $fileIdentifier = $this->canonicalizeAndCheckFileIdentifier(
1136  $parentFolderIdentifier . $this->sanitizeFileName(ltrim($fileName, '/'))
1137  );
1138  $absoluteFilePath = $this->getAbsolutePath($fileIdentifier);
1139  $result = touch($absoluteFilePath);
1140  GeneralUtility::fixPermissions($absoluteFilePath);
1141  clearstatcache();
1142  if ($result !== TRUE) {
1143  throw new \RuntimeException('Creating file ' . $fileIdentifier . ' failed.', 1320569854);
1144  }
1145  return $fileIdentifier;
1146  }
1147 
1157  public function getFileContents($fileIdentifier) {
1158  $filePath = $this->getAbsolutePath($fileIdentifier);
1159  return file_get_contents($filePath);
1160  }
1161 
1170  public function setFileContents($fileIdentifier, $contents) {
1171  $filePath = $this->getAbsolutePath($fileIdentifier);
1172  $result = file_put_contents($filePath, $contents);
1173 
1174  // Make sure later calls to filesize() etc. return correct values.
1175  clearstatcache(TRUE, $filePath);
1176 
1177  if ($result === FALSE) {
1178  throw new \RuntimeException('Setting contents of file "' . $fileIdentifier . '" failed.', 1325419305);
1179  }
1180  return $result;
1181  }
1182 
1188  protected function getCharsetConversion() {
1189  if (!isset($this->charsetConversion)) {
1190  if (TYPO3_MODE === 'FE') {
1191  $this->charsetConversion = $GLOBALS['TSFE']->csConvObj;
1192  } elseif (is_object($GLOBALS['LANG'])) {
1193  // BE assumed:
1194  $this->charsetConversion = $GLOBALS['LANG']->csConvObj;
1195  } else {
1196  // The object may not exist yet, so we need to create it now. Happens in the Install Tool for example.
1197  $this->charsetConversion = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
1198  }
1199  }
1200  return $this->charsetConversion;
1201  }
1202 
1209  public function getRole($folderIdentifier) {
1210  $name = PathUtility::basename($folderIdentifier);
1211  $role = $this->mappingFolderNameToRole[$name];
1212  if (empty($role)) {
1214  }
1215  return $role;
1216  }
1217 
1227  public function dumpFileContents($identifier) {
1228  readfile($this->getAbsolutePath($this->canonicalizeAndCheckFileIdentifier($identifier)), 0);
1229  }
1230 
1231 
1232 }
extractFileInformation($filePath, $containerPath, array $propertiesToExtract=array())
getFoldersInFolder($folderIdentifier, $start=0, $numberOfItems=0, $recursive=FALSE, array $folderNameFilterCallbacks=array())
static mkdir_deep($directory, $deepDirectory='')
applyFilterMethodsToDirectoryItem(array $filterMethods, $itemName, $itemIdentifier, $parentIdentifier)
static isFirstPartOfStr($str, $partStr)
getSpecificFileInformation($fileIdentifier, $containerPath, $property)
copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
deleteFolder($folderIdentifier, $deleteRecursively=FALSE)
const TYPO3_MODE
Definition: init.php:40
static rmdir($path, $removeNonEmpty=FALSE)
static fixPermissions($path, $recursive=FALSE)
hash($fileIdentifier, $hashAlgorithm)
moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
renameFolder($folderIdentifier, $newName)
moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
getDirectoryItemList($folderIdentifier, $start=0, $numberOfItems=0, array $filterMethods, $includeFiles=TRUE, $includeDirs=TRUE, $recursive=FALSE)
getFileForLocalProcessing($fileIdentifier, $writable=TRUE)
addFile($localFilePath, $targetFolderIdentifier, $newFileName='', $removeOriginal=TRUE)
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
createFile($fileName, $parentFolderIdentifier)
__construct(array $configuration=array())
Definition: LocalDriver.php:69
folderExistsInFolder($folderName, $folderIdentifier)
setFileContents($fileIdentifier, $contents)
createFolder($newFolderName, $parentFolderIdentifier='', $recursive=FALSE)
getFolderInFolder($folderName, $folderIdentifier)
getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract=array())
getFilesInFolder($folderIdentifier, $start=0, $numberOfItems=0, $recursive=FALSE, array $filenameFilterCallbacks=array())
replaceFile($fileIdentifier, $localFilePath)
copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
renameFile($fileIdentifier, $newName)
fileExistsInFolder($fileName, $folderIdentifier)
isWithin($folderIdentifier, $identifier)
sanitizeFileName($fileName, $charset='')
createIdentifierMap(array $filesAndFolders, $sourceFolderIdentifier, $targetFolderIdentifier)