/** * Return a public path pointing to a resource. * * @param string $resource * @return string */ public static function getRelativePath($resource) { // If file is not found, resolve the path if (!is_file(PATH_site . $resource)) { $resource = substr(self::resolvePath($resource), strlen(PATH_site)); } return PathUtility::getRelativePathTo(PathUtility::dirname(PATH_site . $resource)) . PathUtility::basename($resource); }
/** * Get url * * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all. * @return string */ public function getUrl($relativeToCurrentScript = false) { $url = $this->url; if ($relativeToCurrentScript && !GeneralUtility::isValidUrl($url)) { $absolutePathToContainingFolder = PathUtility::dirname(PATH_site . $url); $pathPart = PathUtility::getRelativePathTo($absolutePathToContainingFolder); $filePart = substr(PATH_site . $url, strlen($absolutePathToContainingFolder) + 1); $url = $pathPart . $filePart; } return $url; }
/** * Write a file and create the target folder, if the folder do not exists * * @param string $absoluteFileName * @param string $content * * @return bool * @throws Exception */ public static function writeFileAndCreateFolder($absoluteFileName, $content) { $dir = PathUtility::dirname($absoluteFileName) . '/'; if (!is_dir($dir)) { GeneralUtility::mkdir_deep($dir); } if (is_file($absoluteFileName) && !is_writable($absoluteFileName)) { throw new Exception('The autoloader try to add same content to ' . $absoluteFileName . ' but the file is not writable for the autoloader. Please fix it!', 234627835); } return GeneralUtility::writeFile($absoluteFileName, $content); }
/** * Creates a virtual File object to be used transparently by external * metadata extraction services as if it would come from standard FAL. * * @param string $fileName * @param array $metadata * @return \TYPO3\CMS\Core\Resource\File */ protected static function getVirtualFileObject($fileName, array $metadata) { /** @var \TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory */ $resourceFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class); $recordData = ['uid' => 0, 'pid' => 0, 'name' => 'Temporary Upload Storage', 'description' => 'Internal storage, mounting the temporary PHP upload directory.', 'driver' => 'Local', 'processingfolder' => '', 'configuration' => '', 'is_online' => true, 'is_browsable' => false, 'is_public' => false, 'is_writable' => false, 'is_default' => false]; $storageConfiguration = ['basePath' => PathUtility::dirname($fileName), 'pathType' => 'absolute']; $virtualStorage = $resourceFactory->createStorageObject($recordData, $storageConfiguration); $name = PathUtility::basename($fileName); $extension = strtolower(substr($name, strrpos($name, '.') + 1)); /** @var \TYPO3\CMS\Core\Resource\File $virtualFileObject */ $virtualFileObject = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\File::class, ['identifier' => '/' . $name, 'name' => $name, 'extension' => $extension], $virtualStorage, $metadata); return $virtualFileObject; }
/** * Handles the existing files of a Fine Uploader form. * The values are stored in the GET/POST var at the index "fieldValue". * * @return string */ public function getExistingFiles() { $files = array(); $fieldValue = GeneralUtility::_GP('fieldValue'); if ($fieldValue != '') { $imagePath = GeneralUtility::getFileAbsFileName($fieldValue); $imageName = PathUtility::basename($imagePath); $imageDirectoryPath = PathUtility::dirname($imagePath); $imageDirectoryPath = PathUtility::getRelativePath(PATH_site, $imageDirectoryPath); $imageUrl = GeneralUtility::locationHeaderUrl('/' . $imageDirectoryPath . $imageName); if (file_exists($imagePath)) { $files[] = array('name' => $imageName, 'uuid' => $imageUrl, 'thumbnailUrl' => $imageUrl); } } return json_encode($files); }
/** * Handles the existing files of a Fine Uploader form. * The values are stored in the GET/POST var at the index "fieldValue". * * @return string */ public function getExistingFiles() { $files = []; $fieldValue = GeneralUtility::_GP('fieldValue'); if ($fieldValue != '') { // $imagePath = GeneralUtility::getFileAbsFileName($fieldValue); $imagePath = str_replace('new:', '', $fieldValue); $imageName = PathUtility::basename($imagePath); $imageDirectoryPath = PathUtility::dirname($imagePath); $imageDirectoryPath = PathUtility::getRelativePath(PATH_site, $imageDirectoryPath); $imageUrl = GeneralUtility::locationHeaderUrl('/' . $imageDirectoryPath . $imageName); if (file_exists($imagePath)) { $files[] = ['name' => $imageName, 'uuid' => $imageUrl, 'thumbnailUrl' => $imageUrl]; } } return $files; }
/** * @param ResourceStorage $storage * @param AbstractDriver $driver * @param ResourceInterface $resource * @param boolean $relativeToCurrentScript * @param array $urlData */ public function getPublicUrl(ResourceStorage $storage, AbstractDriver $driver, ResourceInterface $resource, $relativeToCurrentScript, array $urlData) { if (!$driver instanceof LocalDriver) { // We cannot handle other files than local files yet return; } $publicUrl = $this->resourcePublisher->getResourceWebUri($resource); if ($publicUrl !== FALSE) { // If requested, make the path relative to the current script in order to make it possible // to use the relative file if ($relativeToCurrentScript) { $publicUrl = PathUtility::getRelativePathTo(PathUtility::dirname(PATH_site . $publicUrl)) . PathUtility::basename($publicUrl); } // $urlData['publicUrl'] is passed by reference, so we can change that here and the value will be taken into account $urlData['publicUrl'] = $publicUrl; } }
/** * Check if the given file is already existing * * @param $path * @param $modelClass * * @return void */ protected function checkCshFile($path, $modelClass) { if (is_file($path)) { return; } $dir = PathUtility::dirname($path); if (!is_dir($dir)) { GeneralUtility::mkdir_deep($dir); } $information = SmartObjectInformationService::getInstance()->getCustomModelFieldTca($modelClass); $properties = array_keys($information); $templatePath = 'Resources/Private/Templates/ContextSensitiveHelp/LanguageDescription.xml'; $standaloneView = GeneralUtility::makeInstance('TYPO3\\CMS\\Fluid\\View\\StandaloneView'); $standaloneView->setTemplatePathAndFilename(ExtensionManagementUtility::extPath('autoloader', $templatePath)); $standaloneView->assign('properties', $properties); $content = $standaloneView->render(); FileUtility::writeFileAndCreateFolder($path, $content); }
/** * Renames a folder in this storage. * * @param string $folderIdentifier * @param string $newName * @return array A map of old to new file identifiers of all affected files and folders * @throws \RuntimeException if renaming the folder failed */ public function renameFolder($folderIdentifier, $newName) { $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier); $newName = $this->sanitizeFileName($newName); $newIdentifier = PathUtility::dirname($folderIdentifier) . '/' . $newName; $newIdentifier = $this->canonicalizeAndCheckFolderIdentifier($newIdentifier); $sourcePath = $this->getAbsolutePath($folderIdentifier); $targetPath = $this->getAbsolutePath($newIdentifier); // get all files and folders we are going to move, to have a map for updating later. $filesAndFolders = $this->retrieveFileAndFoldersInPath($sourcePath, true); $result = rename($sourcePath, $targetPath); if ($result === false) { throw new \RuntimeException(sprintf('Renaming folder "%1$s" to "%2$s" failed."', $sourcePath, $targetPath), 1320375116); } try { // Create a mapping from old to new identifiers $identifierMap = $this->createIdentifierMap($filesAndFolders, $folderIdentifier, $newIdentifier); } catch (\Exception $e) { rename($targetPath, $sourcePath); throw new \RuntimeException(sprintf('Creating filename mapping after renaming "%1$s" to "%2$s" failed. Reverted rename operation.\\n\\nOriginal error: %3$s"', $sourcePath, $targetPath, $e->getMessage()), 1334160746); } return $identifierMap; }
/** * Returns information about a file. * * @param string $fileIdentifier * @param array $propertiesToExtract Array of properties which are be extracted * If empty all will be extracted * @return array * @throws FileDoesNotExistException */ public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = []) { $relativeDriverPath = ltrim($fileIdentifier, '/'); if (!$this->filesystem->has($relativeDriverPath) || !$this->filesystem->get($relativeDriverPath)->isFile()) { throw new FileDoesNotExistException('File ' . $fileIdentifier . ' does not exist.', 1314516809); } $dirPath = PathUtility::dirname($fileIdentifier); $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath); return $this->extractFileInformation($relativeDriverPath, $dirPath, $propertiesToExtract); }
/** * Writes the file with the is $fileId to the legacy import folder. The file name will used from * argument $fileName and the file was successfully created or an identical file was already found, * $fileName will held the uid of the new created file record. * * @param string $fileName The file name for the new file. Value would be changed to the uid of the new created file record. * @param int $fileId The id of the file in data array * @return bool */ protected function writeSysFileResourceForLegacyImport(&$fileName, $fileId) { if ($this->legacyImportFolder === null) { return false; } if (!isset($this->dat['files'][$fileId])) { $this->error('ERROR: File ID "' . $fileId . '" could not be found'); return false; } $temporaryFile = $this->writeTemporaryFileFromData($fileId, 'files'); if ($temporaryFile === null) { // error on writing the file. Error message was already added return false; } $importFolder = $this->legacyImportFolder; if (isset($this->dat['files'][$fileId]['relFileName'])) { $relativeFilePath = PathUtility::dirname($this->dat['files'][$fileId]['relFileName']); if (!$this->legacyImportFolder->hasFolder($relativeFilePath)) { $this->legacyImportFolder->createFolder($relativeFilePath); } $importFolder = $this->legacyImportFolder->getSubfolder($relativeFilePath); } $fileObject = null; try { // check, if there is alreay the same file in the folder if ($importFolder->hasFile($fileName)) { $fileStorage = $importFolder->getStorage(); $file = $fileStorage->getFile($importFolder->getIdentifier() . $fileName); if ($file->getSha1() === sha1_file($temporaryFile)) { $fileObject = $file; } } } catch (Exception $e) { } if ($fileObject === null) { try { $fileObject = $importFolder->addFile($temporaryFile, $fileName, DuplicationBehavior::RENAME); } catch (Exception $e) { $this->error('Error: no file could be added to the storage for file name ' . $this->alternativeFileName[$temporaryFile]); } } if (md5_file(PATH_site . $fileObject->getPublicUrl()) == $this->dat['files'][$fileId]['content_md5']) { $fileName = $fileObject->getUid(); $this->fileIDMap[$fileId] = $fileName; $this->filePathMap[$fileId] = $fileObject->getPublicUrl(); return true; } else { $this->error('ERROR: File content "' . $this->dat['files'][$fileId]['relFileName'] . '" was corrupted'); } return false; }
/** * Compresses a CSS file * * Options: * baseDirectories If set, only include files below one of the base directories * * removes comments and whitespaces * Adopted from http://drupal.org/files/issues/minify_css.php__1.txt * * @param string $filename Source filename, relative to requested page * @return string Compressed filename, relative to requested page */ public function compressCssFile($filename) { // generate the unique name of the file $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $this->getFilenameFromMainDir($filename)); if (@file_exists($filenameAbsolute)) { $fileStatus = stat($filenameAbsolute); $unique = $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size']; } else { $unique = $filenameAbsolute; } $pathinfo = PathUtility::pathinfo($filename); $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.css'; // only create it, if it doesn't exist, yet if (!file_exists((PATH_site . $targetFile)) || $this->createGzipped && !file_exists((PATH_site . $targetFile . '.gzip'))) { $contents = GeneralUtility::getUrl($filenameAbsolute); // Compress CSS Content $contents = $this->compressCssString($contents); // Ensure file ends in newline. // we have to fix relative paths, if we aren't working on a file in our target directory if (strpos($filename, $this->targetDirectory) === FALSE) { $filenameRelativeToMainDir = substr($filename, strlen($this->backPath)); $contents = $this->cssFixRelativeUrlPaths($contents, PathUtility::dirname($filenameRelativeToMainDir) . '/'); } $this->writeFileAndCompressed($targetFile, $contents); } return $this->relativePath . $this->returnFileReference($targetFile); }
/** * Bulk function, can be used for anything to get a file or folder * * 1. It's a UID * 2. It's a combined identifier * 3. It's just a path/filename (coming from the oldstyle/backwards compatibility) * * Files, previously laid on fileadmin/ or something, will be "mapped" to the storage the file is * in now. Files like typo3temp/ or typo3conf/ will be moved to the first writable storage * in its processing folder * * $input could be * - "2:myfolder/myfile.jpg" (combined identifier) * - "23" (file UID) * - "uploads/myfile.png" (backwards-compatibility, storage "0") * - "file:23" * * @param string $input * @return File|Folder */ public function retrieveFileOrFolderObject($input) { // Remove PATH_site because absolute paths under Windows systems contain ':' // This is done in all considered sub functions anyway $input = str_replace(PATH_site, '', $input); if (GeneralUtility::isFirstPartOfStr($input, 'file:')) { $input = substr($input, 5); return $this->retrieveFileOrFolderObject($input); } elseif (MathUtility::canBeInterpretedAsInteger($input)) { return $this->getFileObject($input); } elseif (strpos($input, ':') > 0) { list($prefix) = explode(':', $input); if (MathUtility::canBeInterpretedAsInteger($prefix)) { // path or folder in a valid storageUID return $this->getObjectFromCombinedIdentifier($input); } elseif ($prefix == 'EXT') { $input = GeneralUtility::getFileAbsFileName($input); if (empty($input)) { return null; } $input = PathUtility::getRelativePath(PATH_site, PathUtility::dirname($input)) . PathUtility::basename($input); return $this->getFileObjectFromCombinedIdentifier($input); } else { return null; } } else { // this is a backwards-compatible way to access "0-storage" files or folders // eliminate double slashes, /./ and /../ $input = PathUtility::getCanonicalPath(ltrim($input, '/')); if (@is_file(PATH_site . $input)) { // only the local file return $this->getFileObjectFromCombinedIdentifier($input); } else { // only the local path return $this->getFolderObjectFromCombinedIdentifier($input); } } }
/** * Processes upload of a file. * * @param string $fileName Full path to the file to be processed * @param string $targetFileName Expected target file name, if not converted (only file name, no path) * @param string $targetDirectory * @param \TYPO3\CMS\Core\Resource\File $file * @param \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $backendUser * @param callback $callbackNotification Callback to send notification * @return string File name that was finally written */ public function processFile($fileName, $targetFileName = '', $targetDirectory = '', \TYPO3\CMS\Core\Resource\File $file = null, \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $backendUser = null, $callbackNotification = null) { $this->lastMetadata = null; if (!(empty($targetFileName) && empty($targetDirectory))) { $targetDirectory = rtrim($targetDirectory, '/') . '/'; $ruleset = $this->getRuleset($fileName, $targetDirectory . $targetFileName, $backendUser); } else { $ruleset = $this->getRuleset($fileName, $fileName, $backendUser); } if (count($ruleset) === 0) { // File does not match any rule set return $fileName; } $processedFileName = $this->getProcessedFileName($fileName, $backendUser, $ruleset); if ($processedFileName === null) { // No processing to do return $fileName; } // Make file name relative, store as $targetFileName if (empty($targetFileName)) { $targetFileName = PathUtility::stripPathSitePrefix($fileName); } // Extract the extension if (($dotPosition = strrpos($fileName, '.')) === false) { // File has no extension return $fileName; } $fileExtension = strtolower(substr($fileName, $dotPosition + 1)); if ($fileExtension === 'png' && !$ruleset['resize_png_with_alpha']) { if (ImageUtility::isTransparentPng($fileName)) { $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:image_autoresize/Resources/Private/Language/locallang.xml:message.imageTransparent'), $targetFileName); $this->notify($callbackNotification, $message, \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING); return $fileName; } } if (!is_writable($fileName)) { $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:image_autoresize/Resources/Private/Language/locallang.xml:message.imageNotWritable'), $targetFileName); $this->notify($callbackNotification, $message, \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR); return $fileName; } $targetDestFileName = $fileName; if (isset($ruleset['conversion_mapping'][$fileExtension])) { // File format will be converted $destExtension = $ruleset['conversion_mapping'][$fileExtension]; $destDirectory = PathUtility::dirname($fileName); $destFileName = PathUtility::basename(substr($fileName, 0, strlen($fileName) - strlen($fileExtension)) . $destExtension); if (empty($targetDirectory)) { // Ensures $destFileName does not yet exist, otherwise make it unique! /* @var $fileFunc \TYPO3\CMS\Core\Utility\File\BasicFileUtility */ $fileFunc = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\File\BasicFileUtility::class); $destFileName = $fileFunc->getUniqueName($destFileName, $destDirectory); $targetDestFileName = $destFileName; } else { $destFileName = $destDirectory . '/' . $destFileName; $targetDestFileName = $targetDirectory . PathUtility::basename(substr($targetFileName, 0, strlen($targetFileName) - strlen($fileExtension)) . $destExtension); } } else { // File format stays the same $destExtension = $fileExtension; $destFileName = $fileName; } // Image is bigger than allowed, will now resize it to (hopefully) make it lighter /** @var $gifCreator \TYPO3\CMS\Frontend\Imaging\GifBuilder */ $gifCreator = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Imaging\GifBuilder::class); $gifCreator->init(); $gifCreator->absPrefix = PATH_site; $imParams = $ruleset['keep_metadata'] === '1' ? '###SkipStripProfile###' : ''; $metadata = ImageUtility::getMetadata($fileName, true); $this->lastMetadata = $metadata; $isRotated = false; if ($ruleset['auto_orient'] === '1') { $orientation = ImageUtility::getOrientation($fileName); $isRotated = ImageUtility::isRotated($orientation); $transformation = ImageUtility::getTransformation($orientation); if ($transformation !== '') { $imParams .= ' ' . $transformation; } } if ($isRotated) { // Invert max_width and max_height as the picture // will be automatically rotated $options = array('maxW' => $ruleset['max_height'], 'maxH' => $ruleset['max_width']); } else { $options = array('maxW' => $ruleset['max_width'], 'maxH' => $ruleset['max_height']); } $originalFileSize = filesize($fileName); $tempFileInfo = null; $tempFileInfo = $gifCreator->imageMagickConvert($fileName, $destExtension, '', '', $imParams, '', $options, true); if (filesize($tempFileInfo[3]) >= $originalFileSize - 10240 && $destExtension === $fileExtension) { // Conversion leads to same or bigger file (rounded to 10KB to accomodate tiny variations in compression) => skip! $tempFileInfo = null; } if ($tempFileInfo) { // Signal to post-process the image $this->signalSlotDispatcher->dispatch(__CLASS__, 'afterImageResize', array('operation' => $fileName === $destFileName ? 'RESIZE' : 'RESIZE_CONVERT', 'source' => $fileName, 'destination' => $tempFileInfo[3], 'newWidth' => &$tempFileInfo[0], 'newHeight' => &$tempFileInfo[1])); $newFileSize = filesize($tempFileInfo[3]); $this->reportAdditionalStorageClaimed($originalFileSize - $newFileSize); // Replace original file @unlink($fileName); @rename($tempFileInfo[3], $destFileName); if ($fileName === $destFileName) { $message = sprintf($this->localize('LLL:EXT:image_autoresize/Resources/Private/Language/locallang.xml:message.imageResized'), $targetFileName, $tempFileInfo[0], $tempFileInfo[1]); } else { $message = sprintf($this->localize('LLL:EXT:image_autoresize/Resources/Private/Language/locallang.xml:message.imageResizedAndRenamed'), $targetFileName, $tempFileInfo[0], $tempFileInfo[1], PathUtility::basename($targetDestFileName)); } // Indexation in TYPO3 6.2 is using another signal, after the file // has been actually uploaded $this->lastMetadata['COMPUTED']['Width'] = $tempFileInfo[0]; $this->lastMetadata['COMPUTED']['Height'] = $tempFileInfo[1]; if ($isRotated && $ruleset['keep_metadata'] === '1' && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_version_5'] === 'gm') { ImageUtility::resetOrientation($destFileName); } $this->notify($callbackNotification, $message, \TYPO3\CMS\Core\Messaging\FlashMessage::INFO); } else { // Destination file was not written $destFileName = $fileName; } return $destFileName; }
/** * @param array $items * @param array $filterCallbacks * @return array */ protected function filterItems(array $items, array $filterCallbacks) { foreach ($items as $identifier => $info) { foreach ($filterCallbacks as $filterCallback) { if (is_callable($filterCallback)) { $result = call_user_func($filterCallback, $info['name'], $identifier, PathUtility::dirname($identifier), [], $this); if ($result === -1) { unset($items[$identifier]); break; } elseif ($result === false) { throw new \RuntimeException('Could not apply file/folder name filter ' . $filterCallback[0] . '::' . $filterCallback[1], 1447600899); } } } } return $items; }
/** * Returns the public URL to a file. * * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver) * @return string */ public function getPublicUrl(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $relativeToCurrentScript = false) { if (\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($resource->getIdentifier(), '/_processed_/')) { $publicUrl = '../typo3temp/yag' . $resource->getIdentifier(); // TODO: ....!!!! } else { $item = $resource->getProperty('yagItem'); if (!$item instanceof \Tx_Yag_Domain_Model_Item) { $pathInfo = new PathInfo($resource->getIdentifier()); $item = $this->getItem($pathInfo); } $publicUrl = $this->yagFileSystemDiv->getFileRelFileName($item->getSourceuri()); } if ($relativeToCurrentScript) { $publicUrl = PathUtility::getRelativePathTo(PathUtility::dirname(PATH_site . $publicUrl)) . PathUtility::basename($publicUrl); } return $publicUrl; }
/** * Returns a publicly accessible URL for a file. * * WARNING: Access to the file may be restricted by further means, e.g. * some web-based authentication. You have to take care of this yourself. * * @param ResourceInterface $resourceObject The file or folder object * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver) * @return string */ public function getPublicUrl(ResourceInterface $resourceObject, $relativeToCurrentScript = false) { $publicUrl = null; if ($this->isOnline()) { // Pre-process the public URL by an accordant slot $this->emitPreGeneratePublicUrlSignal($resourceObject, $relativeToCurrentScript, array('publicUrl' => &$publicUrl)); if ($publicUrl === null && $resourceObject instanceof File && ($helper = OnlineMediaHelperRegistry::getInstance()->getOnlineMediaHelper($resourceObject)) !== false) { $publicUrl = $helper->getPublicUrl($resourceObject, $relativeToCurrentScript); } // If slot did not handle the signal, use the default way to determine public URL if ($publicUrl === null) { if ($this->hasCapability(self::CAPABILITY_PUBLIC)) { $publicUrl = $this->driver->getPublicUrl($resourceObject->getIdentifier()); } if ($publicUrl === null && $resourceObject instanceof FileInterface) { $queryParameterArray = array('eID' => 'dumpFile', 't' => ''); if ($resourceObject instanceof File) { $queryParameterArray['f'] = $resourceObject->getUid(); $queryParameterArray['t'] = 'f'; } elseif ($resourceObject instanceof ProcessedFile) { $queryParameterArray['p'] = $resourceObject->getUid(); $queryParameterArray['t'] = 'p'; } $queryParameterArray['token'] = GeneralUtility::hmac(implode('|', $queryParameterArray), 'resourceStorageDumpFile'); $publicUrl = 'index.php?' . str_replace('+', '%20', http_build_query($queryParameterArray)); } // If requested, make the path relative to the current script in order to make it possible // to use the relative file if ($publicUrl !== null && $relativeToCurrentScript && !GeneralUtility::isValidUrl($publicUrl)) { $absolutePathToContainingFolder = PathUtility::dirname(PATH_site . $publicUrl); $pathPart = PathUtility::getRelativePathTo($absolutePathToContainingFolder); $filePart = substr(PATH_site . $publicUrl, strlen($absolutePathToContainingFolder) + 1); $publicUrl = $pathPart . $filePart; } } } return $publicUrl; }
/** * Compresses a CSS file * * Options: * baseDirectories If set, only include files below one of the base directories * * removes comments and whitespaces * Adopted from https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Core/Asset/CssOptimizer.php * * @param string $filename Source filename, relative to requested page * @return string Compressed filename, relative to requested page */ public function compressCssFile($filename) { // generate the unique name of the file $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $this->getFilenameFromMainDir($filename)); if (@file_exists($filenameAbsolute)) { $fileStatus = stat($filenameAbsolute); $unique = $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size']; } else { $unique = $filenameAbsolute; } $pathinfo = PathUtility::pathinfo($filename); $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.css'; // only create it, if it doesn't exist, yet if (!file_exists(PATH_site . $targetFile) || $this->createGzipped && !file_exists(PATH_site . $targetFile . '.gzip')) { $contents = $this->compressCssString(GeneralUtility::getUrl($filenameAbsolute)); if (strpos($filename, $this->targetDirectory) === false) { $contents = $this->cssFixRelativeUrlPaths($contents, PathUtility::dirname($filename) . '/'); } $this->writeFileAndCompressed($targetFile, $contents); } return $this->relativePath . $this->returnFileReference($targetFile); }
/** * Get the path of the nearest recycler folder of a given $path. * Return an empty string if there is no recycler folder available. * * @param string $path * @return string */ protected function getRecycleDirectory($path) { $recyclerSubdirectory = array_search(FolderInterface::ROLE_RECYCLER, $this->mappingFolderNameToRole, true); if ($recyclerSubdirectory === false) { return ''; } $rootDirectory = rtrim($this->getAbsolutePath($this->getRootLevelFolder()), '/'); $searchDirectory = PathUtility::dirname($path); // Check if file or folder to be deleted is inside a recycler directory if ($this->getRole($searchDirectory) === FolderInterface::ROLE_RECYCLER) { $searchDirectory = PathUtility::dirname($searchDirectory); // Check if file or folder to be deleted is inside the root recycler if ($searchDirectory == $rootDirectory) { return ''; } $searchDirectory = PathUtility::dirname($searchDirectory); } // Search for the closest recycler directory while ($searchDirectory) { $recycleDirectory = $searchDirectory . '/' . $recyclerSubdirectory; if (is_dir($recycleDirectory)) { return $recycleDirectory; } elseif ($searchDirectory === $rootDirectory) { return ''; } else { $searchDirectory = PathUtility::dirname($searchDirectory); } } return ''; }
/** * signal slot for public url generation of a file * @see \TYPO3\CMS\Core\Resource\ResourceStorage and the function getPublicUrl * * @param \TYPO3\CMS\Core\Resource\ResourceStorage $t * @param \TYPO3\CMS\Core\Resource\Driver\LocalDriver $driver * @param object $resourceObject e.g. \TYPO3\CMS\Core\Resource\File, \TYPO3\CMS\Core\Resource\Folder, \TYPO3\CMS\Core\Resource\ProcessedFile * @param boolean $relativeToCurrentScript * @param array $urlData * * @return void */ public function preGeneratePublicUrl($t, $driver, $resourceObject, $relativeToCurrentScript, $urlData) { $this->emSettings = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][$this->extKey]); // check if resource is file if (is_a($resourceObject, 'TYPO3\\CMS\\Core\\Resource\\File')) { $fileData = $this->getFileData($resourceObject); $newPublicUrl = ''; $enable = true; // check if TYPO3 is in frontend mode if (TYPO3_MODE === 'FE') { if ($this->emSettings['disable_fe']) { $enable = false; } else { // check filetypes field if (!empty($this->emSettings['filetypes_fe'])) { $filetypes = explode(',', $this->emSettings['filetypes_fe']); if (in_array($fileData['extension'], $filetypes)) { } else { $enable = false; } } if ($enable) { $newPublicUrl = $driver->getPublicUrl($fileData['identifier']); } } } // check if TYPO3 is in backend mode and make the path relative to the current script // in order to make it possible to use the relative file if (TYPO3_MODE === 'BE' && $relativeToCurrentScript) { //DebuggerUtility::var_dump($this->emSettings); if ($this->emSettings['disable_be']) { $enable = false; } else { // check filetypes field if (!empty($this->emSettings['filetypes_be'])) { $filetypes = explode(',', $this->emSettings['filetypes_be']); if (in_array($fileData['extension'], $filetypes)) { } else { $enable = false; } } if ($enable) { $publicUrl = $driver->getPublicUrl($fileData['identifier']); $absolutePathToContainingFolder = PathUtility::dirname(PATH_site . $publicUrl); $pathPart = PathUtility::getRelativePathTo($absolutePathToContainingFolder); $filePart = substr(PATH_site . $publicUrl, strlen($absolutePathToContainingFolder) + 1); $newPublicUrl = $pathPart . $filePart; } } } if (!empty($newPublicUrl) && !empty($fileData['modDate']) && $enable) { $urlData['publicUrl'] = $newPublicUrl . '?v=' . $fileData['modDate']; } } }
/** * Adds a files content to the export memory * * @param array $fI File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile". "relFileName" is optional for files attached to records, but mandatory for soft referenced files (since the relFileName determines where such a file should be stored!) * @param string $recordRef If the file is related to a record, this is the id on the form [table]:[id]. Information purposes only. * @param string $fieldname If the file is related to a record, this is the field name it was related to. Information purposes only. * @return void */ public function export_addFile($fI, $recordRef = '', $fieldname = '') { if (!@is_file($fI['ID_absFile'])) { $this->error($fI['ID_absFile'] . ' was not a file! Skipping.'); return; } if (filesize($fI['ID_absFile']) >= $this->maxFileSize) { $this->error($fI['ID_absFile'] . ' was larger (' . GeneralUtility::formatSize(filesize($fI['ID_absFile'])) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.'); return; } $fileInfo = stat($fI['ID_absFile']); $fileRec = array(); $fileRec['filesize'] = $fileInfo['size']; $fileRec['filename'] = PathUtility::basename($fI['ID_absFile']); $fileRec['filemtime'] = $fileInfo['mtime']; //for internal type file_reference $fileRec['relFileRef'] = PathUtility::stripPathSitePrefix($fI['ID_absFile']); if ($recordRef) { $fileRec['record_ref'] = $recordRef . '/' . $fieldname; } if ($fI['relFileName']) { $fileRec['relFileName'] = $fI['relFileName']; } // Setting this data in the header $this->dat['header']['files'][$fI['ID']] = $fileRec; // ... and for the recordlisting, why not let us know WHICH relations there was... if ($recordRef && $recordRef !== '_SOFTREF_') { $refParts = explode(':', $recordRef, 2); if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) { $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = array(); } $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID']; } $fileMd5 = md5_file($fI['ID_absFile']); if (!$this->saveFilesOutsideExportFile) { // ... and finally add the heavy stuff: $fileRec['content'] = GeneralUtility::getUrl($fI['ID_absFile']); } else { GeneralUtility::upload_copy_move($fI['ID_absFile'], $this->getTemporaryFilesPathForExport() . $fileMd5); } $fileRec['content_md5'] = $fileMd5; $this->dat['files'][$fI['ID']] = $fileRec; // For soft references, do further processing: if ($recordRef === '_SOFTREF_') { // RTE files? if ($RTEoriginal = $this->getRTEoriginalFilename(PathUtility::basename($fI['ID_absFile']))) { $RTEoriginal_absPath = PathUtility::dirname($fI['ID_absFile']) . '/' . $RTEoriginal; if (@is_file($RTEoriginal_absPath)) { $RTEoriginal_ID = md5($RTEoriginal_absPath); $fileInfo = stat($RTEoriginal_absPath); $fileRec = array(); $fileRec['filesize'] = $fileInfo['size']; $fileRec['filename'] = PathUtility::basename($RTEoriginal_absPath); $fileRec['filemtime'] = $fileInfo['mtime']; $fileRec['record_ref'] = '_RTE_COPY_ID:' . $fI['ID']; $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID; // Setting this data in the header $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec; $fileMd5 = md5_file($RTEoriginal_absPath); if (!$this->saveFilesOutsideExportFile) { // ... and finally add the heavy stuff: $fileRec['content'] = GeneralUtility::getUrl($RTEoriginal_absPath); } else { GeneralUtility::upload_copy_move($RTEoriginal_absPath, $this->getTemporaryFilesPathForExport() . $fileMd5); } $fileRec['content_md5'] = $fileMd5; $this->dat['files'][$RTEoriginal_ID] = $fileRec; } else { $this->error('RTE original file "' . PathUtility::stripPathSitePrefix($RTEoriginal_absPath) . '" was not found!'); } } // Files with external media? // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment. $html_fI = pathinfo(PathUtility::basename($fI['ID_absFile'])); if ($this->includeExtFileResources && GeneralUtility::inList($this->extFileResourceExtensions, strtolower($html_fI['extension']))) { $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###'; if (strtolower($html_fI['extension']) === 'css') { $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i', '\\1' . $uniquePrefix . '\\2' . $uniquePrefix . '\\3', $fileRec['content'])); } else { // html, htm: $htmlParser = GeneralUtility::makeInstance(HtmlParser::class); $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix, $fileRec['content'], array(), $uniquePrefix)); } $htmlResourceCaptured = false; foreach ($prefixedMedias as $k => $v) { if ($k % 2) { $EXTres_absPath = GeneralUtility::resolveBackPath(PathUtility::dirname($fI['ID_absFile']) . '/' . $v); $EXTres_absPath = GeneralUtility::getFileAbsFileName($EXTres_absPath); if ($EXTres_absPath && GeneralUtility::isFirstPartOfStr($EXTres_absPath, PATH_site . $this->fileadminFolderName . '/') && @is_file($EXTres_absPath)) { $htmlResourceCaptured = true; $EXTres_ID = md5($EXTres_absPath); $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID; $prefixedMedias[$k] = '{EXT_RES_ID:' . $EXTres_ID . '}'; // Add file to memory if it is not set already: if (!isset($this->dat['header']['files'][$EXTres_ID])) { $fileInfo = stat($EXTres_absPath); $fileRec = array(); $fileRec['filesize'] = $fileInfo['size']; $fileRec['filename'] = PathUtility::basename($EXTres_absPath); $fileRec['filemtime'] = $fileInfo['mtime']; $fileRec['record_ref'] = '_EXT_PARENT_:' . $fI['ID']; // Media relative to the HTML file. $fileRec['parentRelFileName'] = $v; // Setting this data in the header $this->dat['header']['files'][$EXTres_ID] = $fileRec; // ... and finally add the heavy stuff: $fileRec['content'] = GeneralUtility::getUrl($EXTres_absPath); $fileRec['content_md5'] = md5($fileRec['content']); $this->dat['files'][$EXTres_ID] = $fileRec; } } } } if ($htmlResourceCaptured) { $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias); } } } }
/** * Returns information about a file. * * @param string $fileIdentifier * @param array $propertiesToExtract Array of properties which are be extracted * If empty all will be extracted * @return array */ public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = array()) { $dirPath = PathUtility::dirname($fileIdentifier); $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath); if (empty($propertiesToExtract)) { $propertiesToExtract = array('size', 'atime', 'atime', 'mtime', 'ctime', 'mimetype', 'name', 'identifier', 'identifier_hash', 'storage', 'folder_hash'); } $fileInformation = array(); foreach ($propertiesToExtract as $property) { $fileInformation[$property] = $this->getSpecificFileInformation($fileIdentifier, $dirPath, $property); } return $fileInformation; }
/** * Compresses a CSS file * * Options: * baseDirectories If set, only include files below one of the base directories * * removes comments and whitespaces * Adopted from http://drupal.org/files/issues/minify_css.php__1.txt * * @param string $filename Source filename, relative to requested page * @return string Compressed filename, relative to requested page */ public function compressCssFile($filename) { // generate the unique name of the file $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $this->getFilenameFromMainDir($filename)); if (@file_exists($filenameAbsolute)) { $fileStatus = stat($filenameAbsolute); $unique = $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size']; } else { $unique = $filenameAbsolute; } $pathinfo = PathUtility::pathinfo($filename); $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.css'; // only create it, if it doesn't exist, yet if (!file_exists(PATH_site . $targetFile) || $this->createGzipped && !file_exists(PATH_site . $targetFile . '.gzip')) { $contents = GeneralUtility::getUrl($filenameAbsolute); // Perform some safe CSS optimizations. $contents = str_replace(CR, '', $contents); // Strip any and all carriage returns. // Match and process strings, comments and everything else, one chunk at a time. // To understand this regex, read: "Mastering Regular Expressions 3rd Edition" chapter 6. $contents = preg_replace_callback('% # One-regex-to-rule-them-all! - version: 20100220_0100 # Group 1: Match a double quoted string. ("[^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+") | # or... # Group 2: Match a single quoted string. (\'[^\'\\\\]*+(?:\\\\.[^\'\\\\]*+)*+\') | # or... # Group 3: Match a regular non-MacIE5-hack comment. (/\\*[^\\\\*]*+\\*++(?:[^\\\\*/][^\\\\*]*+\\*++)*+/) | # or... # Group 4: Match a MacIE5-type1 comment. (/\\*(?:[^*\\\\]*+\\**+(?!/))*+\\\\[^*]*+\\*++(?:[^*/][^*]*+\\*++)*+/(?<!\\\\\\*/)) | # or... # Group 5: Match a MacIE5-type2 comment. (/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*/(?<=\\\\\\*/)) # folllowed by... # Group 6: Match everything up to final closing regular comment ([^/]*+(?:(?!\\*)/[^/]*+)*?) # Group 7: Match final closing regular comment (/\\*[^/]++(?:(?<!\\*)/(?!\\*)[^/]*+)*+/(?<=(?<!\\\\)\\*/)) | # or... # Group 8: Match regular non-string, non-comment text. ([^"\'/]*+(?:(?!/\\*)/[^"\'/]*+)*+) %Ssx', array('self', 'compressCssPregCallback'), $contents); // Do it! $contents = preg_replace('/^\\s++/', '', $contents); // Strip leading whitespace. $contents = preg_replace('/[ \\t]*+\\n\\s*+/S', ' ', $contents); // Consolidate multi-lines space. $contents = preg_replace('/(?<!\\s)\\s*+$/S', ' ', $contents); // Ensure file ends in newline. // we have to fix relative paths, if we aren't working on a file in our target directory if (strpos($filename, $this->targetDirectory) === FALSE) { $filenameRelativeToMainDir = substr($filename, strlen($this->backPath)); $contents = $this->cssFixRelativeUrlPaths($contents, PathUtility::dirname($filenameRelativeToMainDir) . '/'); } $this->writeFileAndCompressed($targetFile, $contents); } return $this->relativePath . $this->returnFileReference($targetFile); }
/** * Returns the identifier of the folder the file resides in * * @param string $fileIdentifier * @return mixed */ public function getParentFolderIdentifierOfIdentifier($fileIdentifier) { $fileIdentifier = $this->canonicalizeAndCheckFileIdentifier($fileIdentifier); return PathUtility::dirname($fileIdentifier) . '/'; }
/** * Creates the index entry for a given file. * * @param string $fileName * @param integer $width * @param integer $height * @return void */ protected static function createIndex($fileName, $width, $height) { $relativePath = substr(PathUtility::dirname($fileName), strlen(PATH_site)); $resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance(); $targetFolder = $resourceFactory->retrieveFileOrFolderObject($relativePath); $targetFilename = PathUtility::basename($fileName); $storageConfiguration = $targetFolder->getStorage()->getConfiguration(); if (!isset($storageConfiguration['basePath'])) { // Probably a file found in uploads/ or similar return; } $basePath = rtrim($storageConfiguration['basePath'], '/') . '/'; $basePath = GeneralUtility::getFileAbsFileName($basePath); $identifier = substr($fileName, strlen($basePath) - 1); // TODO: possibly create file with nearly no info and populate them with // a call to $file->getStorage()->getFileInfo($file) instead of using $driver /** @var \TYPO3\CMS\Core\Resource\Driver\AbstractDriver $driver */ $driver = static::accessProtectedProperty($targetFolder->getStorage(), 'driver'); $fileInfo = $driver->getFileInfoByIdentifier($identifier); $file = $resourceFactory->createFileObject($fileInfo); /** @var \TYPO3\CMS\Core\Resource\FileRepository $fileRepository */ $fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class); $fileRepository->addToIndex($file); }
/** * Add file relation entries for a record's rels-array * * @param array $rels Array of file IDs * @param array $lines Output lines array (is passed by reference and modified) * @param string $preCode Pre-HTML code * @param string $htmlColorClass Alternative HTML color class to use. * @param string $tokenID Token ID if this is a softreference (in which case it only makes sense with a single element in the $rels array!) * @return void * @access private * @see singleRecordLines() */ public function addFiles($rels, &$lines, $preCode, $htmlColorClass = '', $tokenID = '') { foreach ($rels as $ID) { // Process file: $pInfo = array(); $fI = $this->dat['header']['files'][$ID]; if (!is_array($fI)) { if (!$tokenID || $this->includeSoftref($tokenID)) { $pInfo['msg'] = 'MISSING FILE: ' . $ID; $this->error('MISSING FILE: ' . $ID); } else { return; } } $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('status-status-reference-hard', Icon::SIZE_SMALL)->render(); $pInfo['title'] = htmlspecialchars($fI['filename']); $pInfo['ref'] = 'FILE'; $pInfo['size'] = $fI['filesize']; $pInfo['class'] = $htmlColorClass ?: 'bgColor3'; $pInfo['type'] = 'file'; // If import mode and there is a non-RTE softreference, check the destination directory: if ($this->mode === 'import' && $tokenID && !$fI['RTE_ORIG_ID']) { if (isset($fI['parentRelFileName'])) { $pInfo['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. '; } else { $testDirPrefix = PathUtility::dirname($fI['relFileName']) . '/'; $testDirPrefix2 = $this->verifyFolderAccess($testDirPrefix); if (!$testDirPrefix2) { $pInfo['msg'] = 'ERROR: There are no available filemounts to write file in! '; } elseif ($testDirPrefix !== $testDirPrefix2) { $pInfo['msg'] = 'File will be attempted written to "' . $testDirPrefix2 . '". '; } } // Check if file exists: if (file_exists(PATH_site . $fI['relFileName'])) { if ($this->update) { $pInfo['updatePath'] .= 'File exists.'; } else { $pInfo['msg'] .= 'File already exists! '; } } // Check extension: $fileProcObj = $this->getFileProcObj(); if ($fileProcObj->actionPerms['addFile']) { $testFI = GeneralUtility::split_fileref(PATH_site . $fI['relFileName']); if (!$this->allowPHPScripts && !$fileProcObj->checkIfAllowed($testFI['fileext'], $testFI['path'], $testFI['file'])) { $pInfo['msg'] .= 'File extension was not allowed!'; } } else { $pInfo['msg'] = 'You user profile does not allow you to create files on the server!'; } } $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$ID]); $lines[] = $pInfo; unset($this->remainHeader['files'][$ID]); // RTE originals: if ($fI['RTE_ORIG_ID']) { $ID = $fI['RTE_ORIG_ID']; $pInfo = array(); $fI = $this->dat['header']['files'][$ID]; if (!is_array($fI)) { $pInfo['msg'] = 'MISSING RTE original FILE: ' . $ID; $this->error('MISSING RTE original FILE: ' . $ID); } $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$ID]); $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('status-status-reference-hard', Icon::SIZE_SMALL)->render(); $pInfo['title'] = htmlspecialchars($fI['filename']) . ' <em>(Original)</em>'; $pInfo['ref'] = 'FILE'; $pInfo['size'] = $fI['filesize']; $pInfo['class'] = $htmlColorClass ?: 'bgColor3'; $pInfo['type'] = 'file'; $lines[] = $pInfo; unset($this->remainHeader['files'][$ID]); } // External resources: if (is_array($fI['EXT_RES_ID'])) { foreach ($fI['EXT_RES_ID'] as $extID) { $pInfo = array(); $fI = $this->dat['header']['files'][$extID]; if (!is_array($fI)) { $pInfo['msg'] = 'MISSING External Resource FILE: ' . $extID; $this->error('MISSING External Resource FILE: ' . $extID); } else { $pInfo['updatePath'] = $fI['parentRelFileName']; } $pInfo['showDiffContent'] = PathUtility::stripPathSitePrefix($this->fileIDMap[$extID]); $pInfo['preCode'] = $preCode . ' ' . $this->iconFactory->getIcon('actions-insert-reference', Icon::SIZE_SMALL)->render(); $pInfo['title'] = htmlspecialchars($fI['filename']) . ' <em>(Resource)</em>'; $pInfo['ref'] = 'FILE'; $pInfo['size'] = $fI['filesize']; $pInfo['class'] = $htmlColorClass ?: 'bgColor3'; $pInfo['type'] = 'file'; $lines[] = $pInfo; unset($this->remainHeader['files'][$extID]); } } } }
/** * Create file in directory and return the new (unique) filename * * @param string $origDirPrefix Directory prefix, relative, with trailing slash * @param string $fileName Filename (without path) * @param string $fileID File ID from import memory * @param string $table Table for which the processing occurs * @param string $uid UID of record from table * @return string|NULL New relative filename, if any */ public function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid) { // If the fileID map contains an entry for this fileID then just return the relative filename of that entry; // we don't want to write another unique filename for this one! if (isset($this->fileIDMap[$fileID])) { return PathUtility::stripPathSitePrefix($this->fileIDMap[$fileID]); } // Verify FileMount access to dir-prefix. Returns the best alternative relative path if any $dirPrefix = $this->verifyFolderAccess($origDirPrefix); if ($dirPrefix && (!$this->update || $origDirPrefix === $dirPrefix) && $this->checkOrCreateDir($dirPrefix)) { $fileHeaderInfo = $this->dat['header']['files'][$fileID]; $updMode = $this->update && $this->import_mapId[$table][$uid] === $uid && $this->import_mode[$table . ':' . $uid] !== 'as_new'; // Create new name for file: // Must have same ID in map array (just for security, is not really needed) and NOT be set "as_new". // Write main file: if ($updMode) { $newName = PATH_site . $dirPrefix . $fileName; } else { // Create unique filename: $fileProcObj = $this->getFileProcObj(); $newName = $fileProcObj->getUniqueName($fileName, PATH_site . $dirPrefix); } if ($this->writeFileVerify($newName, $fileID)) { // If the resource was an HTML/CSS file with resources attached, we will write those as well! if (is_array($fileHeaderInfo['EXT_RES_ID'])) { $tokenizedContent = $this->dat['files'][$fileID]['tokenizedContent']; $tokenSubstituted = false; $fileProcObj = $this->getFileProcObj(); if ($updMode) { foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) { if ($this->dat['files'][$res_fileID]['filename']) { // Resolve original filename: $relResourceFileName = $this->dat['files'][$res_fileID]['parentRelFileName']; $absResourceFileName = GeneralUtility::resolveBackPath(PATH_site . $origDirPrefix . $relResourceFileName); $absResourceFileName = GeneralUtility::getFileAbsFileName($absResourceFileName); if ($absResourceFileName && GeneralUtility::isFirstPartOfStr($absResourceFileName, PATH_site . $this->fileadminFolderName . '/')) { $destDir = PathUtility::stripPathSitePrefix(PathUtility::dirname($absResourceFileName) . '/'); if ($this->verifyFolderAccess($destDir, true) && $this->checkOrCreateDir($destDir)) { $this->writeFileVerify($absResourceFileName, $res_fileID); } else { $this->error('ERROR: Could not create file in directory "' . $destDir . '"'); } } else { $this->error('ERROR: Could not resolve path for "' . $relResourceFileName . '"'); } $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent); $tokenSubstituted = true; } } } else { // Create the resouces directory name (filename without extension, suffixed "_FILES") $resourceDir = PathUtility::dirname($newName) . '/' . preg_replace('/\\.[^.]*$/', '', PathUtility::basename($newName)) . '_FILES'; if (GeneralUtility::mkdir($resourceDir)) { foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) { if ($this->dat['files'][$res_fileID]['filename']) { $absResourceFileName = $fileProcObj->getUniqueName($this->dat['files'][$res_fileID]['filename'], $resourceDir); $relResourceFileName = substr($absResourceFileName, strlen(PathUtility::dirname($resourceDir)) + 1); $this->writeFileVerify($absResourceFileName, $res_fileID); $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent); $tokenSubstituted = true; } } } } // If substitutions has been made, write the content to the file again: if ($tokenSubstituted) { GeneralUtility::writeFile($newName, $tokenizedContent); } } return PathUtility::stripPathSitePrefix($newName); } } return null; }