/**
  * Publishes the given source stream to this target, with the given relative path.
  *
  * @param resource $sourceStream Stream of the source to publish
  * @param string $relativeTargetPathAndFilename relative path and filename in the target directory
  * @throws Exception
  * @throws \TYPO3\Flow\Utility\Exception
  */
 protected function publishFile($sourceStream, $relativeTargetPathAndFilename)
 {
     $pathInfo = UnicodeFunctions::pathinfo($relativeTargetPathAndFilename);
     if (isset($pathInfo['extension']) && array_key_exists(strtolower($pathInfo['extension']), $this->extensionBlacklist) && $this->extensionBlacklist[strtolower($pathInfo['extension'])] === true) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the filename extension "%s" is blacklisted.', $sourceStream, $this->name, strtolower($pathInfo['extension'])), 1447152230);
     }
     $streamMetaData = stream_get_meta_data($sourceStream);
     if ($streamMetaData['wrapper_type'] !== 'plainfile' || $streamMetaData['stream_type'] !== 'STDIO') {
         throw new Exception(sprintf('Could not publish stream "%s" into resource publishing target "%s" because the source is not a local file.', $streamMetaData['uri'], $this->name), 1416242392);
     }
     $sourcePathAndFilename = $streamMetaData['uri'];
     $targetPathAndFilename = $this->path . $relativeTargetPathAndFilename;
     if (@stat($sourcePathAndFilename) === false) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file is not accessible (file stat failed).', $sourcePathAndFilename, $this->name), 1415716366);
     }
     if (!file_exists(dirname($targetPathAndFilename))) {
         Files::createDirectoryRecursively(dirname($targetPathAndFilename));
     }
     try {
         if (Files::is_link($targetPathAndFilename)) {
             Files::unlink($targetPathAndFilename);
         }
         $temporaryTargetPathAndFilename = uniqid($targetPathAndFilename . '.') . '.tmp';
         symlink($sourcePathAndFilename, $temporaryTargetPathAndFilename);
         $result = rename($temporaryTargetPathAndFilename, $targetPathAndFilename);
     } catch (\Exception $exception) {
         $result = false;
     }
     if ($result === false) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file could not be symlinked at target location.', $sourcePathAndFilename, $this->name), 1415716368, isset($exception) ? $exception : null);
     }
     $this->systemLogger->log(sprintf('FileSystemSymlinkTarget: Published file. (target: %s, file: %s)', $this->name, $relativeTargetPathAndFilename), LOG_DEBUG);
 }
 /**
  * Return all Objects stored in this storage filtered by the given directory / filename pattern
  *
  * @param string $pattern A glob compatible directory / filename pattern
  * @param callable $callback Function called after each object
  * @return \Generator<StorageObject>
  */
 public function getObjectsByPathPattern($pattern, callable $callback = null)
 {
     $directories = [];
     if (strpos($pattern, '/') !== false) {
         list($packageKeyPattern, $directoryPattern) = explode('/', $pattern, 2);
     } else {
         $packageKeyPattern = $pattern;
         $directoryPattern = '*';
     }
     // $packageKeyPattern can be used in a future implementation to filter by package key
     $packages = $this->packageManager->getActivePackages();
     foreach ($packages as $packageKey => $package) {
         /** @var PackageInterface $package */
         if ($directoryPattern === '*') {
             $directories[$packageKey][] = $package->getPackagePath();
         } else {
             $directories[$packageKey] = glob($package->getPackagePath() . $directoryPattern, GLOB_ONLYDIR);
         }
     }
     $iteration = 0;
     foreach ($directories as $packageKey => $packageDirectories) {
         foreach ($packageDirectories as $directoryPath) {
             foreach (Files::getRecursiveDirectoryGenerator($directoryPath) as $resourcePathAndFilename) {
                 $pathInfo = UnicodeFunctions::pathinfo($resourcePathAndFilename);
                 $object = new Object();
                 $object->setFilename($pathInfo['basename']);
                 $object->setSha1(sha1_file($resourcePathAndFilename));
                 $object->setMd5(md5_file($resourcePathAndFilename));
                 $object->setFileSize(filesize($resourcePathAndFilename));
                 if (isset($pathInfo['dirname'])) {
                     list(, $path) = explode('/', str_replace($packages[$packageKey]->getResourcesPath(), '', $pathInfo['dirname']), 2);
                     $object->setRelativePublicationPath($packageKey . '/' . $path . '/');
                 }
                 $object->setStream(function () use($resourcePathAndFilename) {
                     return fopen($resourcePathAndFilename, 'r');
                 });
                 (yield $object);
                 if (is_callable($callback)) {
                     call_user_func($callback, $iteration, $object);
                 }
                 $iteration++;
             }
         }
     }
 }
 /**
  * Prepare an uploaded file to be imported as resource object. Will check the validity of the file,
  * move it outside of upload folder if open_basedir is enabled and check the filename.
  *
  * @param array $uploadInfo
  * @return array Array of string with the two keys "filepath" (the path to get the filecontent from) and "filename" the filename of the originally uploaded file.
  * @throws Exception
  */
 protected function prepareUploadedFileForImport(array $uploadInfo)
 {
     $openBasedirEnabled = (bool) ini_get('open_basedir');
     $temporaryTargetPathAndFilename = $uploadInfo['tmp_name'];
     $pathInfo = UnicodeFunctions::pathinfo($uploadInfo['name']);
     if (!is_uploaded_file($temporaryTargetPathAndFilename)) {
         throw new Exception('The given upload file "' . strip_tags($pathInfo['basename']) . '" was not uploaded through PHP. As it could pose a security risk it cannot be imported.', 1422461503);
     }
     if ($openBasedirEnabled === TRUE) {
         // Move uploaded file to a readable folder before trying to read sha1 value of file
         $newTemporaryTargetPathAndFilename = $this->environment->getPathToTemporaryDirectory() . 'ResourceUpload.' . uniqid() . '.tmp';
         if (move_uploaded_file($temporaryTargetPathAndFilename, $newTemporaryTargetPathAndFilename) === FALSE) {
             throw new Exception(sprintf('The uploaded file "%s" could not be moved to the temporary location "%s".', $temporaryTargetPathAndFilename, $newTemporaryTargetPathAndFilename), 1375199056);
         }
         $temporaryTargetPathAndFilename = $newTemporaryTargetPathAndFilename;
     }
     if (!is_file($temporaryTargetPathAndFilename)) {
         throw new Exception(sprintf('The temporary file "%s" of the file upload does not exist (anymore).', $temporaryTargetPathAndFilename), 1375198998);
     }
     return array('filepath' => $temporaryTargetPathAndFilename, 'filename' => $pathInfo['basename']);
 }
 /**
  * Sets the filename which is used when this resource is downloaded or saved as a file
  *
  * @param string $filename
  * @return void
  * @api
  */
 public function setFilename($filename)
 {
     $this->throwExceptionIfProtected();
     $pathInfo = UnicodeFunctions::pathinfo($filename);
     $extension = isset($pathInfo['extension']) ? '.' . strtolower($pathInfo['extension']) : '';
     $this->filename = $pathInfo['filename'] . $extension;
     $this->mediaType = MediaTypes::getMediaTypeFromFilename($this->filename);
 }
 /**
  * @param FlowResource $originalResource
  * @param array $adjustments
  * @return array resource, width, height as keys
  * @throws ImageFileException
  * @throws InvalidConfigurationException
  * @throws \TYPO3\Flow\Resource\Exception
  */
 public function processImage(FlowResource $originalResource, array $adjustments)
 {
     $additionalOptions = array();
     $adjustmentsApplied = false;
     // TODO: Special handling for SVG should be refactored at a later point.
     if ($originalResource->getMediaType() === 'image/svg+xml') {
         $originalResourceStream = $originalResource->getStream();
         $resource = $this->resourceManager->importResource($originalResourceStream, $originalResource->getCollectionName());
         fclose($originalResourceStream);
         $resource->setFilename($originalResource->getFilename());
         return ['width' => null, 'height' => null, 'resource' => $resource];
     }
     $resourceUri = $originalResource->createTemporaryLocalCopy();
     $resultingFileExtension = $originalResource->getFileExtension();
     $transformedImageTemporaryPathAndFilename = $this->environment->getPathToTemporaryDirectory() . uniqid('ProcessedImage-') . '.' . $resultingFileExtension;
     if (!file_exists($resourceUri)) {
         throw new ImageFileException(sprintf('An error occurred while transforming an image: the resource data of the original image does not exist (%s, %s).', $originalResource->getSha1(), $resourceUri), 1374848224);
     }
     $imagineImage = $this->imagineService->open($resourceUri);
     if ($this->imagineService instanceof \Imagine\Imagick\Imagine && $originalResource->getFileExtension() === 'gif' && $this->isAnimatedGif(file_get_contents($resourceUri)) === true) {
         $imagineImage->layers()->coalesce();
         $layers = $imagineImage->layers();
         $newLayers = array();
         foreach ($layers as $index => $imagineFrame) {
             $imagineFrame = $this->applyAdjustments($imagineFrame, $adjustments, $adjustmentsApplied);
             $newLayers[] = $imagineFrame;
         }
         $imagineImage = array_shift($newLayers);
         $layers = $imagineImage->layers();
         foreach ($newLayers as $imagineFrame) {
             $layers->add($imagineFrame);
         }
         $additionalOptions['animated'] = true;
     } else {
         $imagineImage = $this->applyAdjustments($imagineImage, $adjustments, $adjustmentsApplied);
     }
     if ($adjustmentsApplied === true) {
         $imagineImage->save($transformedImageTemporaryPathAndFilename, $this->getOptionsMergedWithDefaults($additionalOptions));
         $imageSize = $imagineImage->getSize();
         // TODO: In the future the collectionName of the new resource should be configurable.
         $resource = $this->resourceManager->importResource($transformedImageTemporaryPathAndFilename, $originalResource->getCollectionName());
         if ($resource === false) {
             throw new ImageFileException('An error occurred while importing a generated image file as a resource.', 1413562208);
         }
         unlink($transformedImageTemporaryPathAndFilename);
         $pathInfo = UnicodeFunctions::pathinfo($originalResource->getFilename());
         $resource->setFilename(sprintf('%s-%ux%u.%s', $pathInfo['filename'], $imageSize->getWidth(), $imageSize->getHeight(), $pathInfo['extension']));
     } else {
         $originalResourceStream = $originalResource->getStream();
         $resource = $this->resourceManager->importResource($originalResourceStream, $originalResource->getCollectionName());
         fclose($originalResourceStream);
         $resource->setFilename($originalResource->getFilename());
         $imageSize = $this->getImageSize($originalResource);
         $imageSize = new Box($imageSize['width'], $imageSize['height']);
     }
     $this->imageSizeCache->set($resource->getCacheEntryIdentifier(), array('width' => $imageSize->getWidth(), 'height' => $imageSize->getHeight()));
     $result = array('width' => $imageSize->getWidth(), 'height' => $imageSize->getHeight(), 'resource' => $resource);
     return $result;
 }
 /**
  * Publishes the given source stream to this target, with the given relative path.
  *
  * @param resource $sourceStream Stream of the source to publish
  * @param string $relativeTargetPathAndFilename relative path and filename in the target directory
  * @return void
  * @throws Exception
  * @throws \Exception
  * @throws \TYPO3\Flow\Utility\Exception
  */
 protected function publishFile($sourceStream, $relativeTargetPathAndFilename)
 {
     $pathInfo = UnicodeFunctions::pathinfo($relativeTargetPathAndFilename);
     if (isset($pathInfo['extension']) && array_key_exists(strtolower($pathInfo['extension']), $this->extensionBlacklist) && $this->extensionBlacklist[strtolower($pathInfo['extension'])] === true) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the filename extension "%s" is blacklisted.', $sourceStream, $this->name, strtolower($pathInfo['extension'])), 1447148472);
     }
     $targetPathAndFilename = $this->path . $relativeTargetPathAndFilename;
     if (@fstat($sourceStream) === false) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file is not accessible (file stat failed).', $sourceStream, $this->name), 1375258499);
     }
     if (!file_exists(dirname($targetPathAndFilename))) {
         Files::createDirectoryRecursively(dirname($targetPathAndFilename));
     }
     if (!is_writable(dirname($targetPathAndFilename))) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the target file "%s" is not writable.', $sourceStream, $this->name, $targetPathAndFilename), 1428917322, isset($exception) ? $exception : null);
     }
     try {
         $targetFileHandle = fopen($targetPathAndFilename, 'w');
         $result = stream_copy_to_stream($sourceStream, $targetFileHandle);
         fclose($targetFileHandle);
     } catch (\Exception $exception) {
         $result = false;
     }
     if ($result === false) {
         throw new Exception(sprintf('Could not publish "%s" into resource publishing target "%s" because the source file could not be copied to the target location.', $sourceStream, $this->name), 1375258399, isset($exception) ? $exception : null);
     }
     $this->systemLogger->log(sprintf('FileSystemTarget: Published file. (target: %s, file: %s)', $this->name, $relativeTargetPathAndFilename), LOG_DEBUG);
 }
 /**
  * Checks if our version of pathinfo can handle some common special characters
  *
  * @test
  */
 public function pathinfoWorksWithCertainSpecialChars()
 {
     $testString = 'кириллическийПуть/кириллическоеИмя.расширение';
     $this->assertEquals('кириллическийПуть', \TYPO3\Flow\Utility\Unicode\Functions::pathinfo($testString, PATHINFO_DIRNAME), 'pathinfo() did not return the correct dirname for a unicode path.');
     $this->assertEquals('кириллическоеИмя.расширение', \TYPO3\Flow\Utility\Unicode\Functions::pathinfo($testString, PATHINFO_BASENAME), 'pathinfo() did not return the correct basename for a unicode path.');
     $this->assertEquals('расширение', \TYPO3\Flow\Utility\Unicode\Functions::pathinfo($testString, PATHINFO_EXTENSION), 'pathinfo() did not return the correct extension for a unicode path.');
     $this->assertEquals('кириллическоеИмя', \TYPO3\Flow\Utility\Unicode\Functions::pathinfo($testString, PATHINFO_FILENAME), 'pathinfo() did not return the correct filename for a unicode path.');
 }