2 namespace TYPO3\CMS\Core\Resource\Driver;
106 if ($this->baseUri === null) {
135 if ($temporaryBaseUri !==
'') {
136 $uriParts = explode(
'/', $temporaryBaseUri);
137 $uriParts = array_map(
'rawurlencode', $uriParts);
138 $temporaryBaseUri = implode(
'/', $uriParts) .
'/';
140 $this->baseUri = $temporaryBaseUri;
142 $this->baseUri = rtrim($this->configuration[
'baseUri'],
'/') .
'/';
156 if (!array_key_exists(
'basePath', $configuration) || empty($configuration[
'basePath'])) {
157 throw new Exception\InvalidConfigurationException(
158 'Configuration must contain base path.',
163 if ($configuration[
'pathType'] ===
'relative') {
164 $relativeBasePath = $configuration[
'basePath'];
172 throw new Exception\InvalidConfigurationException(
191 if ($this->baseUri !== null) {
192 $uriParts = explode(
'/', ltrim($identifier,
'/'));
193 $uriParts = array_map(
'rawurlencode', $uriParts);
194 $identifier = implode(
'/', $uriParts);
195 $publicUrl = $this->baseUri . $identifier;
217 $identifier =
'/user_upload/';
219 if ($createFolder ===
true) {
234 public function createFolder($newFolderName, $parentFolderIdentifier =
'', $recursive =
false)
237 $newFolderName = trim($newFolderName,
'/');
238 if ($recursive ==
false) {
240 $newIdentifier = $parentFolderIdentifier . $newFolderName .
'/';
244 $parts = array_map(array($this,
'sanitizeFileName'), $parts);
245 $newFolderName = implode(
'/', $parts);
246 $newIdentifier = $parentFolderIdentifier . $newFolderName .
'/';
249 return $newIdentifier;
265 if (!file_exists($absoluteFilePath) || !is_file($absoluteFilePath)) {
266 throw new \InvalidArgumentException(
'File ' . $fileIdentifier .
' does not exist.', 1314516809);
286 throw new Exception\FolderDoesNotExistException(
287 'Folder "' . $folderIdentifier .
'" does not exist.',
292 'identifier' => $folderIdentifier,
294 'storage' => $this->storageUid
313 if (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SYS'][
'UTF8filesystem']) {
315 $cleanFileName = preg_replace(
'/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION .
']/u',
'_', trim($fileName));
319 if (TYPO3_MODE ===
'FE') {
320 $charset =
$GLOBALS[
'TSFE']->renderCharset;
331 $cleanFileName = preg_replace(
'/[' . self::UNSAFE_FILENAME_CHARACTER_EXPRESSION .
'\\xC0-\\xFF]/',
'_', trim($fileName));
334 $cleanFileName = rtrim($cleanFileName,
'.');
335 if ($cleanFileName ===
'') {
336 throw new Exception\InvalidFileNameException(
337 'File name ' . $fileName .
' is invalid.',
341 return $cleanFileName;
363 protected function getDirectoryItemList($folderIdentifier, $start = 0, $numberOfItems = 0, array $filterMethods, $includeFiles =
true, $includeDirs =
true, $recursive =
false, $sort =
'', $sortRev =
false)
367 if (!is_dir($realPath)) {
368 throw new \InvalidArgumentException(
369 'Cannot list items in directory ' . $folderIdentifier .
' - does not exist or is no directory',
378 $items = $this->retrieveFileAndFoldersInPath($realPath, $recursive, $includeFiles, $includeDirs, $sort, $sortRev);
379 $iterator = new \ArrayIterator($items);
380 if ($iterator->count() === 0) {
383 $iterator->seek($start);
386 $c = $numberOfItems > 0 ? $numberOfItems : - 1;
388 while ($iterator->valid() && ($numberOfItems === 0 || $c > 0)) {
390 $iteratorItem = $iterator->current();
397 $iteratorItem[
'name'],
398 $iteratorItem[
'identifier'],
405 $items[$iteratorItem[
'identifier']] = $iteratorItem[
'identifier'];
427 foreach ($filterMethods as $filter) {
428 if (is_callable($filter)) {
429 $result = call_user_func($filter, $itemName, $itemIdentifier, $parentIdentifier, array(), $this);
432 if ($result === -1) {
434 }
elseif ($result ===
false) {
435 throw new \RuntimeException(
'Could not apply file/folder name filter ' . $filter[0] .
'::' . $filter[1]);
470 public function getFilesInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive =
false, array $filenameFilterCallbacks = array(), $sort =
'', $sortRev =
false)
472 return $this->
getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $filenameFilterCallbacks,
true,
false, $recursive, $sort, $sortRev);
483 public function countFilesInFolder($folderIdentifier, $recursive =
false, array $filenameFilterCallbacks = array())
485 return count($this->
getFilesInFolder($folderIdentifier, 0, 0, $recursive, $filenameFilterCallbacks));
504 public function getFoldersInFolder($folderIdentifier, $start = 0, $numberOfItems = 0, $recursive =
false, array $folderNameFilterCallbacks = array(), $sort =
'', $sortRev =
false)
506 return $this->
getDirectoryItemList($folderIdentifier, $start, $numberOfItems, $folderNameFilterCallbacks,
false,
true, $recursive, $sort, $sortRev);
517 public function countFoldersInFolder($folderIdentifier, $recursive =
false, array $folderNameFilterCallbacks = array())
519 return count($this->
getFoldersInFolder($folderIdentifier, 0, 0, $recursive, $folderNameFilterCallbacks));
537 protected function retrieveFileAndFoldersInPath($path, $recursive =
false, $includeFiles =
true, $includeDirs =
true, $sort =
'', $sortRev =
false)
540 $iteratorMode = \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::FOLLOW_SYMLINKS;
542 $iterator = new \RecursiveIteratorIterator(
543 new \RecursiveDirectoryIterator($path, $iteratorMode),
544 \RecursiveIteratorIterator::SELF_FIRST
547 $iterator = new \RecursiveDirectoryIterator($path, $iteratorMode);
550 $directoryEntries = array();
551 while ($iterator->valid()) {
553 $entry = $iterator->current();
555 if ((!$entry->isFile() && !$entry->isDir()) || $entry->getFilename() ==
'' ||
556 ($entry->isFile() && !$includeFiles) || ($entry->isDir() && !$includeDirs)) {
560 $entryIdentifier =
'/' . substr($entry->getPathname(), $pathLength);
562 if ($entry->isDir()) {
563 $entryIdentifier .=
'/';
566 'identifier' => $entryIdentifier,
567 'name' => $entryName,
568 'type' => $entry->isDir() ?
'dir' :
'file'
570 $directoryEntries[$entryIdentifier] = $entryArray;
591 $entriesToSort = array();
592 foreach ($directoryEntries as $entryArray) {
593 $dir = pathinfo($entryArray[
'name'], PATHINFO_DIRNAME) .
'/';
597 if ($entryArray[
'type'] ===
'file') {
598 $sortingKey = $this->getSpecificFileInformation($fullPath, $dir,
'size');
605 $sortingKey = ($perms[
'r'] ?
'R' :
'')
606 . ($perms[
'w'] ?
'W' :
'');
609 $sortingKey = pathinfo($entryArray[
'name'], PATHINFO_EXTENSION);
612 if ($entryArray[
'type'] ===
'file') {
613 $sortingKey = $this->getSpecificFileInformation($fullPath, $dir,
'mtime');
621 $sortingKey = $entryArray[
'name'];
624 while (isset($entriesToSort[$sortingKey . $i])) {
627 $entriesToSort[$sortingKey . $i] = $entryArray;
629 uksort($entriesToSort,
'strnatcasecmp');
632 $entriesToSort = array_reverse($entriesToSort);
635 return $entriesToSort;
648 if (empty($propertiesToExtract)) {
649 $propertiesToExtract = array(
650 'size',
'atime',
'atime',
'mtime',
'ctime',
'mimetype',
'name',
651 'identifier',
'identifier_hash',
'storage',
'folder_hash'
654 $fileInformation = array();
655 foreach ($propertiesToExtract as $property) {
656 $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
658 return $fileInformation;
672 public function getSpecificFileInformation($fileIdentifier, $containerPath, $property)
680 return $fileInfo->getSize();
682 return $fileInfo->getATime();
684 return $fileInfo->getMTime();
686 return $fileInfo->getCTime();
690 return (
string)$fileInfo->getMimeType();
695 case 'identifier_hash':
700 throw new \InvalidArgumentException(sprintf(
'The information "%s" is not available.', $property));
724 $path = $this->absoluteBasePath . $relativeFilePath;
737 public function hash($fileIdentifier, $hashAlgorithm)
739 if (!in_array($hashAlgorithm, $this->supportedHashAlgorithms)) {
740 throw new \InvalidArgumentException(
'Hash algorithm "' . $hashAlgorithm .
'" is not supported.', 1304964032);
742 switch ($hashAlgorithm) {
750 throw new \RuntimeException(
'Hash algorithm ' . $hashAlgorithm .
' is not implemented.', 1329644451);
768 public function addFile($localFilePath, $targetFolderIdentifier, $newFileName =
'', $removeOriginal =
true)
775 throw new \InvalidArgumentException(
'Cannot add a file that is already part of this storage.', 1314778269);
781 if ($removeOriginal) {
782 if (is_uploaded_file($localFilePath)) {
783 $result = move_uploaded_file($localFilePath, $targetPath);
785 $result = rename($localFilePath, $targetPath);
788 $result = copy($localFilePath, $targetPath);
790 if ($result ===
false || !file_exists($targetPath)) {
791 throw new \RuntimeException(
'Adding file ' . $localFilePath .
' at ' . $newFileIdentifier .
' failed.');
796 return $newFileIdentifier;
809 return is_file($absoluteFilePath);
821 $identifier = $folderIdentifier .
'/' . $fileName;
836 return is_dir($absoluteFilePath);
848 $identifier = $folderIdentifier .
'/' . $folderName;
863 return $folderIdentifier;
877 $result = rename($localFilePath, $filePath);
879 if ($result ===
false) {
880 throw new \RuntimeException(
'Replacing file ' . $fileIdentifier .
' with ' . $localFilePath .
' failed.', 1315314711);
898 $newIdentifier = $targetFolderIdentifier .
'/' . $fileName;
902 copy($sourcePath, $absoluteFilePath);
904 return $newIdentifier;
921 $targetIdentifier = $targetFolderIdentifier .
'/' . $newFileName;
923 $result = rename($sourcePath, $this->
getAbsolutePath($targetIdentifier));
924 if ($result ===
false) {
925 throw new \RuntimeException(
'Moving file ' . $sourcePath .
' to ' . $targetIdentifier .
' failed.', 1315314712);
927 return $targetIdentifier;
941 $result = copy($sourcePath, $temporaryPath);
942 touch($temporaryPath, filemtime($sourcePath));
943 if ($result ===
false) {
944 throw new \RuntimeException(
945 'Copying file "' . $fileIdentifier .
'" to temporary path "' . $temporaryPath .
'" failed.',
949 return $temporaryPath;
963 protected function createIdentifierMap(array $filesAndFolders, $sourceFolderIdentifier, $targetFolderIdentifier)
965 $identifierMap = array();
966 $identifierMap[$sourceFolderIdentifier] = $targetFolderIdentifier;
967 foreach ($filesAndFolders as $oldItem) {
968 if ($oldItem[
'type'] ==
'dir') {
969 $oldIdentifier = $oldItem[
'identifier'];
971 str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem[
'identifier'])
974 $oldIdentifier = $oldItem[
'identifier'];
976 str_replace($sourceFolderIdentifier, $targetFolderIdentifier, $oldItem[
'identifier'])
980 throw new Exception\FileOperationErrorException(
981 sprintf(
'File "%1$s" was not found (should have been copied/moved from "%2$s").', $newIdentifier, $oldIdentifier),
985 $identifierMap[$oldIdentifier] = $newIdentifier;
987 return $identifierMap;
1006 $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath,
true);
1007 $result = rename($sourcePath, $targetPath);
1008 if ($result ===
false) {
1009 throw new \RuntimeException(
'Moving folder ' . $sourcePath .
' to ' . $targetPath .
' failed.', 1320711817);
1012 $identifierMap = $this->
createIdentifierMap($filesAndFolders, $sourceFolderIdentifier, $relativeTargetPath);
1013 return $identifierMap;
1034 mkdir($targetFolderPath);
1036 $iterator = new \RecursiveIteratorIterator(
1037 new \RecursiveDirectoryIterator($sourceFolderPath),
1038 \RecursiveIteratorIterator::SELF_FIRST
1041 $iterator->rewind();
1042 while ($iterator->valid()) {
1044 $current = $iterator->current();
1045 $fileName = $current->getFilename();
1047 if ($current->isDir() && !($fileName ===
'..' || $fileName ===
'.')) {
1049 }
elseif ($current->isFile()) {
1050 $result = copy($sourceFolderPath .
'/' . $itemSubPath, $targetFolderPath .
'/' . $itemSubPath);
1051 if ($result ===
false) {
1054 throw new Exception\FileOperationErrorException(
1055 'Copying file "' . $sourceFolderPath . $itemSubPath .
'" to "' . $targetFolderPath . $itemSubPath .
'" failed.',
1083 throw new Exception\ExistingTargetFileNameException(
1084 'The target file "' . $newIdentifier .
'" already exists.',
1090 $result = rename($sourcePath, $targetPath);
1091 if ($result ===
false) {
1092 throw new \RuntimeException(
'Renaming file ' . $sourcePath .
' to ' . $targetPath .
' failed.', 1320375115);
1094 return $newIdentifier;
1117 $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath,
true);
1118 $result = rename($sourcePath, $targetPath);
1119 if ($result ===
false) {
1120 throw new \RuntimeException(sprintf(
'Renaming folder "%1$s" to "%2$s" failed."', $sourcePath, $targetPath), 1320375116);
1124 $identifierMap = $this->
createIdentifierMap($filesAndFolders, $folderIdentifier, $newIdentifier);
1126 rename($targetPath, $sourcePath);
1127 throw new \RuntimeException(
1129 'Creating filename mapping after renaming "%1$s" to "%2$s" failed. Reverted rename operation.\\n\\nOriginal error: %3$s"',
1130 $sourcePath, $targetPath, $e->getMessage()
1135 return $identifierMap;
1150 $result = unlink($filePath);
1151 if ($result ===
false) {
1152 throw new \RuntimeException(
'Deletion of file ' . $fileIdentifier .
' failed.', 1320855304);
1166 public function deleteFolder($folderIdentifier, $deleteRecursively =
false)
1170 if ($result ===
false) {
1171 throw new Exception\FileOperationErrorException(
1172 'Deleting folder "' . $folderIdentifier .
'" failed.',
1188 $dirHandle = opendir($path);
1189 while ($entry = readdir($dirHandle)) {
1190 if ($entry !==
'.' && $entry !==
'..') {
1191 closedir($dirHandle);
1195 closedir($dirHandle);
1211 if ($writable ===
false) {
1229 $permissionBits = fileperms($path);
1230 if ($permissionBits ===
false) {
1231 throw new Exception\ResourcePermissionsUnavailableException(
'Error while fetching permissions for ' . $path, 1319455097);
1234 'r' => (
bool)is_readable($path),
1235 'w' => (
bool)is_writable($path)
1248 public function isWithin($folderIdentifier, $identifier)
1252 if ($folderIdentifier === $entryIdentifier) {
1257 if ($folderIdentifier !==
'/') {
1258 $folderIdentifier .=
'/';
1275 throw new Exception\InvalidFileNameException(
1276 'Invalid characters in fileName "' . $fileName .
'"',
1285 $result = touch($absoluteFilePath);
1288 if ($result !==
true) {
1289 throw new \RuntimeException(
'Creating file ' . $fileIdentifier .
' failed.', 1320569854);
1291 return $fileIdentifier;
1306 return file_get_contents($filePath);
1320 $result = file_put_contents($filePath, $contents);
1323 clearstatcache(
true, $filePath);
1325 if ($result ===
false) {
1326 throw new \RuntimeException(
'Setting contents of file "' . $fileIdentifier .
'" failed.', 1325419305);
1338 if (!isset($this->charsetConversion)) {
1339 if (TYPO3_MODE ===
'FE') {
1340 $this->charsetConversion =
$GLOBALS[
'TSFE']->csConvObj;
1343 $this->charsetConversion =
$GLOBALS[
'LANG']->csConvObj;
1361 $role = $this->mappingFolderNameToRole[$name];