/**
  * Publishes the given persistent resource from the given storage
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource to publish
  * @param CollectionInterface $collection The collection the given resource belongs to
  * @return void
  * @throws Exception
  */
 public function publishResource(Resource $resource, CollectionInterface $collection)
 {
     $sourceStream = $resource->getStream();
     if ($sourceStream === FALSE) {
         throw new Exception(sprintf('Could not publish resource %s with SHA1 hash %s of collection %s because there seems to be no corresponding data in the storage.', $resource->getFilename(), $resource->getSha1(), $collection->getName()), 1375258146);
     }
     $this->publishFile($sourceStream, $this->getRelativePublicationPathAndFilename($resource));
     fclose($sourceStream);
 }
 /**
  * Returns a stream handle which can be used internally to open / copy the given resource
  * stored in this storage.
  *
  * @param PersistentResource $resource The resource stored in this storage
  * @return resource | boolean The resource stream or FALSE if the stream could not be obtained
  */
 public function getStreamByResource(PersistentResource $resource)
 {
     $pathAndFilename = $this->getStoragePathAndFilenameByHash($resource->getSha1());
     return file_exists($pathAndFilename) ? fopen($pathAndFilename, 'rb') : false;
 }
 /**
  * Deletes the storage data related to the given Resource object
  *
  * @param PersistentResource $resource The Resource to delete the storage data of
  * @return boolean TRUE if removal was successful
  */
 public function deleteResource(PersistentResource $resource)
 {
     $pathAndFilename = $this->getStoragePathAndFilenameByHash($resource->getSha1());
     if (!file_exists($pathAndFilename)) {
         return true;
     }
     if (unlink($pathAndFilename) === false) {
         return false;
     }
     Files::removeEmptyDirectoriesOnPath(dirname($pathAndFilename));
     return true;
 }
 /**
  * {@inheritDoc}
  */
 public function getSha1()
 {
     $this->__initializer__ && $this->__initializer__->__invoke($this, 'getSha1', array());
     return parent::getSha1();
 }
 /**
  * Deletes the given Resource from the Resource Repository and, if the storage data is no longer used in another
  * Resource object, also deletes the data from the storage.
  *
  * This method will also remove the Resource object from the (internal) ResourceRepository.
  *
  * @param Resource $resource The resource to delete
  * @param boolean $unpublishResource If the resource should be unpublished before deleting it from the storage
  * @return boolean TRUE if the resource was deleted, otherwise FALSE
  * @api
  */
 public function deleteResource(Resource $resource, $unpublishResource = TRUE)
 {
     $collectionName = $resource->getCollectionName();
     $result = $this->resourceRepository->findBySha1($resource->getSha1());
     if (count($result) > 1) {
         $this->systemLogger->log(sprintf('Not removing storage data of resource %s (%s) because it is still in use by %s other Resource object(s).', $resource->getFilename(), $resource->getSha1(), count($result) - 1), LOG_DEBUG);
     } else {
         if (!isset($this->collections[$collectionName])) {
             $this->systemLogger->log(sprintf('Could not remove storage data of resource %s (%s) because it refers to the unknown collection "%s".', $resource->getFilename(), $resource->getSha1(), $collectionName), LOG_WARNING);
             return FALSE;
         }
         $storage = $this->collections[$collectionName]->getStorage();
         if (!$storage instanceof WritableStorageInterface) {
             $this->systemLogger->log(sprintf('Could not remove storage data of resource %s (%s) because it its collection "%s" is read-only.', $resource->getFilename(), $resource->getSha1(), $collectionName), LOG_WARNING);
             return FALSE;
         }
         try {
             $storage->deleteResource($resource);
         } catch (\Exception $exception) {
             $this->systemLogger->log(sprintf('Could not remove storage data of resource %s (%s): %s.', $resource->getFilename(), $resource->getSha1(), $exception->getMessage()), LOG_WARNING);
             return FALSE;
         }
         if ($unpublishResource) {
             /** @var TargetInterface $target */
             $target = $this->collections[$collectionName]->getTarget();
             $target->unpublishResource($resource);
             $this->systemLogger->log(sprintf('Removed storage data and unpublished resource %s (%s) because it not used by any other Resource object.', $resource->getFilename(), $resource->getSha1()), LOG_DEBUG);
         } else {
             $this->systemLogger->log(sprintf('Removed storage data of resource %s (%s) because it not used by any other Resource object.', $resource->getFilename(), $resource->getSha1()), LOG_DEBUG);
         }
     }
     $resource->setDeleted();
     $this->resourceRepository->remove($resource);
     return TRUE;
 }
 /**
  * @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;
 }
 /**
  * Returns the web accessible URI pointing to the specified persistent resource
  *
  * @param Resource $resource Resource object
  * @return string The URI
  * @throws Exception
  */
 public function getPublicPersistentResourceUri(Resource $resource)
 {
     $resourceData = array('resourceIdentifier' => $resource->getSha1());
     if ($this->shouldIncludeSecurityContext()) {
         $resourceData['securityContextHash'] = $this->securityContext->getContextHash();
     } elseif (!empty($this->options['tokenLifetime'])) {
         $expirationDateTime = clone $this->now;
         $expirationDateTime = $expirationDateTime->modify(sprintf('+%d seconds', $this->options['tokenLifetime']));
         $resourceData['expirationDateTime'] = $expirationDateTime->format(\DateTime::ISO8601);
     }
     $encodedResourceData = base64_encode(json_encode($resourceData));
     $signedResourceData = $this->hashService->appendHmac($encodedResourceData);
     return $this->detectResourcesBaseUri() . '?__protectedResource=' . $signedResourceData;
 }
 /**
  * Publishes the given persistent resource from the given storage
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource to publish
  * @param CollectionInterface $collection The collection the given resource belongs to
  * @return void
  * @throws Exception
  */
 public function publishResource(Resource $resource, CollectionInterface $collection)
 {
     if ($this->debug) {
         $this->systemLogger->log('target ' . $this->name . ': publishResource');
     }
     $storage = $collection->getStorage();
     if ($storage instanceof KeyCDNStorage) {
         if ($storage->getContainerName() === $this->containerName) {
             throw new Exception(sprintf('Could not publish resource with SHA1 hash %s of collection %s because the source and target container is the same.', $resource->getSha1(), $collection->getName()), 1375348223);
         }
         $temporaryTargetPathAndFilename = $this->environment->getPathToTemporaryDirectory() . uniqid('TYPO3_Flow_ResourceImport_');
         $this->downloadFile($temporaryTargetPathAndFilename, '_' . $resource->getSha1());
         $this->uploadFile($temporaryTargetPathAndFilename, $this->getRelativePublicationPathAndFilename($resource));
     } else {
         $sourceStream = $collection->getStreamByResource($resource);
         if ($sourceStream === FALSE) {
             throw new Exception(sprintf('Could not publish resource with SHA1 hash %s of collection %s because there seems to be no corresponding data in the storage.', $resource->getSha1(), $collection->getName()), 1375342304);
         }
         $this->publishFile($sourceStream, $this->getRelativePublicationPathAndFilename($resource), $resource);
     }
 }
 /**
  * Finds other resources which are referring to the same resource data and filename
  *
  * @param Resource $resource The resource used for finding similar resources
  * @return QueryResultInterface The result, including the given resource
  */
 public function findSimilarResources(Resource $resource)
 {
     $query = $this->createQuery();
     $query->matching($query->logicalAnd($query->equals('sha1', $resource->getSha1()), $query->equals('filename', $resource->getFilename())));
     return $query->execute();
 }
Example #10
0
 /**
  * Returns a stream handle which can be used internally to open / copy the given resource
  * stored in this storage.
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource stored in this storage
  * @return resource | boolean A URI (for example the full path and filename) leading to the resource file or FALSE if it does not exist
  * @api
  */
 public function getStreamByResource(Resource $resource)
 {
     try {
         return fopen('s3://' . $this->bucketName . '/' . $this->keyPrefix . $resource->getSha1(), 'r');
     } catch (\Exception $e) {
         if (strpos($e->getMessage(), '<Code>NoSuchKey</Code>') !== false) {
             return false;
         }
         $message = sprintf('Could not retrieve stream for resource %s (s3://%s/%s%s). %s', $resource->getFilename(), $this->bucketName, $this->keyPrefix, $resource->getSha1(), $e->getMessage());
         $this->systemLogger->log($message, \LOG_ERR);
         throw new Exception($message, 1445682605);
     }
 }
Example #11
0
 /**
  * Publishes the given persistent resource from the given storage
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource to publish
  * @param CollectionInterface $collection The collection the given resource belongs to
  * @return void
  * @throws Exception
  */
 public function publishResource(Resource $resource, CollectionInterface $collection)
 {
     $storage = $collection->getStorage();
     if ($storage instanceof S3Storage) {
         if ($storage->getBucketName() === $this->bucketName && $storage->getKeyPrefix() === $this->keyPrefix) {
             throw new Exception(sprintf('Could not publish resource with SHA1 hash %s of collection %s because the source and target S3 bucket is the same, with identical key prefixes. Either choose a different bucket or at least key prefix for the target.', $resource->getSha1(), $collection->getName()), 1428929563);
         }
         try {
             $sourceObjectArn = $storage->getBucketName() . '/' . $storage->getKeyPrefix() . $resource->getSha1();
             $objectName = $this->keyPrefix . $this->getRelativePublicationPathAndFilename($resource);
             $options = array('ACL' => 'public-read', 'Bucket' => $this->bucketName, 'CopySource' => urlencode($sourceObjectArn), 'ContentType' => $resource->getMediaType(), 'MetadataDirective' => 'REPLACE', 'Key' => $objectName);
             $this->s3Client->copyObject($options);
             $this->systemLogger->log(sprintf('Successfully published resource as object "%s" (MD5: %s) by copying from bucket "%s" to bucket "%s"', $objectName, $resource->getMd5() ?: 'unknown', $storage->getBucketName(), $this->bucketName), LOG_DEBUG);
         } catch (S3Exception $e) {
             throw new Exception(sprintf('Could not publish resource with SHA1 hash %s of collection %s (source object: %s) through "CopyObject" because the S3 client reported an error: %s', $resource->getSha1(), $collection->getName(), $sourceObjectArn, $e->getMessage()), 1428999574);
         }
     } else {
         $sourceStream = $resource->getStream();
         if ($sourceStream === false) {
             throw new Exception(sprintf('Could not publish resource with SHA1 hash %s of collection %s because there seems to be no corresponding data in the storage.', $resource->getSha1(), $collection->getName()), 1428929649);
         }
         $this->publishFile($sourceStream, $this->getRelativePublicationPathAndFilename($resource), $resource);
     }
 }
Example #12
0
 /**
  * Returns a stream handle which can be used internally to open / copy the given resource
  * stored in this storage.
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource stored in this storage
  * @return resource | boolean A URI (for example the full path and filename) leading to the resource file or FALSE if it does not exist
  * @api
  */
 public function getStreamByResource(Resource $resource)
 {
     return fopen('s3://' . $this->bucketName . '/' . $this->keyPrefix . $resource->getSha1(), 'r');
 }
 /**
  * Deletes the storage data related to the given Resource object
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The Resource to delete the storage data of
  * @return boolean TRUE if removal was successful
  */
 public function deleteResource(Resource $resource)
 {
     $pathAndFilename = $this->getStoragePathAndFilenameByHash($resource->getSha1());
     if (!file_exists($pathAndFilename)) {
         return TRUE;
     }
     if (unlink($pathAndFilename) === FALSE) {
         return FALSE;
     }
     Files::removeEmptyDirectoriesOnPath(dirname($pathAndFilename));
     return TRUE;
 }
 /**
  * Returns a stream handle which can be used internally to open / copy the given resource
  * stored in this storage.
  *
  * @param \TYPO3\Flow\Resource\Resource $resource The resource stored in this storage
  * @return resource | boolean A URI (for example the full path and filename) leading to the resource file or FALSE if it does not exist
  * @api
  */
 public function getStreamByResource(Resource $resource)
 {
     if ($this->debug) {
         $this->systemLogger->log('storage ' . $this->name . ': getStreamByResource');
     }
     if ($this->ftpService->fileExists('_' . $resource->getSha1())) {
         if ($this->debug) {
             $this->systemLogger->log('storage ' . $this->name . ': - getStreamByResource ' . 'http://' . $this->zoneDomain . '/_' . $resource->getSha1());
         }
         return fopen('http://' . $this->zoneDomain . '/_' . $resource->getSha1(), 'r');
     } else {
         if ($this->debug) {
             $this->systemLogger->log('storage ' . $this->name . ': - getStreamByResource file _' . $resource->getSha1() . ' not exists');
         }
         return FALSE;
     }
 }