Media.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <?php
  2. /**
  3. * Media application
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\MediaStorage\App;
  9. use Magento\Catalog\Model\View\Asset\PlaceholderFactory;
  10. use Magento\Framework\App\State;
  11. use Magento\Framework\Filesystem;
  12. use Magento\MediaStorage\Model\File\Storage\ConfigFactory;
  13. use Magento\MediaStorage\Model\File\Storage\Response;
  14. use Magento\Framework\App;
  15. use Magento\Framework\App\Filesystem\DirectoryList;
  16. use Magento\Framework\AppInterface;
  17. use Magento\MediaStorage\Model\File\Storage\SynchronizationFactory;
  18. use Magento\Framework\App\Area;
  19. use Magento\MediaStorage\Model\File\Storage\Config;
  20. use Magento\MediaStorage\Service\ImageResize;
  21. /**
  22. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  23. */
  24. class Media implements AppInterface
  25. {
  26. /**
  27. * Authorization function
  28. *
  29. * @var \Closure
  30. */
  31. private $isAllowed;
  32. /**
  33. * Media directory path
  34. *
  35. * @var string
  36. */
  37. private $mediaDirectoryPath;
  38. /**
  39. * Configuration cache file path
  40. *
  41. * @var string
  42. */
  43. private $configCacheFile;
  44. /**
  45. * Requested file name relative to working directory
  46. *
  47. * @var string
  48. */
  49. private $relativeFileName;
  50. /**
  51. * @var Response
  52. */
  53. private $response;
  54. /**
  55. * @var \Magento\Framework\Filesystem\Directory\WriteInterface
  56. */
  57. private $directory;
  58. /**
  59. * @var ConfigFactory
  60. */
  61. private $configFactory;
  62. /**
  63. * @var SynchronizationFactory
  64. */
  65. private $syncFactory;
  66. /**
  67. * @var PlaceholderFactory
  68. */
  69. private $placeholderFactory;
  70. /**
  71. * @var State
  72. */
  73. private $appState;
  74. /**
  75. * @var ImageResize
  76. */
  77. private $imageResize;
  78. /**
  79. * @param ConfigFactory $configFactory
  80. * @param SynchronizationFactory $syncFactory
  81. * @param Response $response
  82. * @param \Closure $isAllowed
  83. * @param string $mediaDirectory
  84. * @param string $configCacheFile
  85. * @param string $relativeFileName
  86. * @param Filesystem $filesystem
  87. * @param PlaceholderFactory $placeholderFactory
  88. * @param State $state
  89. * @param ImageResize $imageResize
  90. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  91. */
  92. public function __construct(
  93. ConfigFactory $configFactory,
  94. SynchronizationFactory $syncFactory,
  95. Response $response,
  96. \Closure $isAllowed,
  97. $mediaDirectory,
  98. $configCacheFile,
  99. $relativeFileName,
  100. Filesystem $filesystem,
  101. PlaceholderFactory $placeholderFactory,
  102. State $state,
  103. ImageResize $imageResize
  104. ) {
  105. $this->response = $response;
  106. $this->isAllowed = $isAllowed;
  107. $this->directory = $filesystem->getDirectoryWrite(DirectoryList::PUB);
  108. $mediaDirectory = trim($mediaDirectory);
  109. if (!empty($mediaDirectory)) {
  110. $this->mediaDirectoryPath = str_replace('\\', '/', realpath($mediaDirectory));
  111. }
  112. $this->configCacheFile = $configCacheFile;
  113. $this->relativeFileName = $relativeFileName;
  114. $this->configFactory = $configFactory;
  115. $this->syncFactory = $syncFactory;
  116. $this->placeholderFactory = $placeholderFactory;
  117. $this->appState = $state;
  118. $this->imageResize = $imageResize;
  119. }
  120. /**
  121. * Run application
  122. *
  123. * @return Response
  124. * @throws \LogicException
  125. */
  126. public function launch()
  127. {
  128. $this->appState->setAreaCode(Area::AREA_GLOBAL);
  129. if ($this->mediaDirectoryPath !== $this->directory->getAbsolutePath()) {
  130. // Path to media directory changed or absent - update the config
  131. /** @var Config $config */
  132. $config = $this->configFactory->create(['cacheFile' => $this->configCacheFile]);
  133. $config->save();
  134. $this->mediaDirectoryPath = $config->getMediaDirectory();
  135. $allowedResources = $config->getAllowedResources();
  136. $isAllowed = $this->isAllowed;
  137. if (!$isAllowed($this->relativeFileName, $allowedResources)) {
  138. throw new \LogicException('The specified path is not allowed.');
  139. }
  140. }
  141. try {
  142. /** @var \Magento\MediaStorage\Model\File\Storage\Synchronization $sync */
  143. $sync = $this->syncFactory->create(['directory' => $this->directory]);
  144. $sync->synchronize($this->relativeFileName);
  145. $this->imageResize->resizeFromImageName($this->getOriginalImage($this->relativeFileName));
  146. if ($this->directory->isReadable($this->relativeFileName)) {
  147. $this->response->setFilePath($this->directory->getAbsolutePath($this->relativeFileName));
  148. } else {
  149. $this->setPlaceholderImage();
  150. }
  151. } catch (\Exception $e) {
  152. $this->setPlaceholderImage();
  153. }
  154. return $this->response;
  155. }
  156. private function setPlaceholderImage()
  157. {
  158. $placeholder = $this->placeholderFactory->create(['type' => 'image']);
  159. $this->response->setFilePath($placeholder->getPath());
  160. }
  161. /**
  162. * Find the path to the original image of the cache path
  163. *
  164. * @param string $resizedImagePath
  165. * @return string
  166. */
  167. private function getOriginalImage(string $resizedImagePath): string
  168. {
  169. return preg_replace('|^.*((?:/[^/]+){3})$|', '$1', $resizedImagePath);
  170. }
  171. /**
  172. * {@inheritdoc}
  173. */
  174. public function catchException(App\Bootstrap $bootstrap, \Exception $exception)
  175. {
  176. $this->response->setHttpResponseCode(404);
  177. if ($bootstrap->isDeveloperMode()) {
  178. $this->response->setHeader('Content-Type', 'text/plain');
  179. $this->response->setBody($exception->getMessage() . "\n" . $exception->getTraceAsString());
  180. }
  181. $this->response->sendResponse();
  182. return true;
  183. }
  184. }