StaticResource.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\App;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. use Magento\Framework\ObjectManager\ConfigLoaderInterface;
  9. use Magento\Framework\Filesystem;
  10. use Magento\Framework\Config\ConfigOptionsListConstants;
  11. use Psr\Log\LoggerInterface;
  12. use Magento\Framework\Debug;
  13. /**
  14. * Entry point for retrieving static resources like JS, CSS, images by requested public path
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. */
  18. class StaticResource implements \Magento\Framework\AppInterface
  19. {
  20. /**
  21. * @var \Magento\Framework\App\State
  22. */
  23. private $state;
  24. /**
  25. * @var \Magento\Framework\App\Response\FileInterface
  26. */
  27. private $response;
  28. /**
  29. * @var \Magento\Framework\App\Request\Http
  30. */
  31. private $request;
  32. /**
  33. * @var \Magento\Framework\App\View\Asset\Publisher
  34. */
  35. private $publisher;
  36. /**
  37. * @var \Magento\Framework\View\Asset\Repository
  38. */
  39. private $assetRepo;
  40. /**
  41. * @var \Magento\Framework\Module\ModuleList
  42. */
  43. private $moduleList;
  44. /**
  45. * @var \Magento\Framework\ObjectManagerInterface
  46. */
  47. private $objectManager;
  48. /**
  49. * @var \Magento\Framework\ObjectManager\ConfigLoaderInterface
  50. */
  51. private $configLoader;
  52. /**
  53. * @var \Magento\Framework\Filesystem
  54. */
  55. private $filesystem;
  56. /**
  57. * @var DeploymentConfig
  58. */
  59. private $deploymentConfig;
  60. /**
  61. * @var \Psr\Log\LoggerInterface
  62. */
  63. private $logger;
  64. /**
  65. * @param State $state
  66. * @param Response\FileInterface $response
  67. * @param Request\Http $request
  68. * @param View\Asset\Publisher $publisher
  69. * @param \Magento\Framework\View\Asset\Repository $assetRepo
  70. * @param \Magento\Framework\Module\ModuleList $moduleList
  71. * @param \Magento\Framework\ObjectManagerInterface $objectManager
  72. * @param ConfigLoaderInterface $configLoader
  73. * @param DeploymentConfig|null $deploymentConfig
  74. */
  75. public function __construct(
  76. State $state,
  77. Response\FileInterface $response,
  78. Request\Http $request,
  79. View\Asset\Publisher $publisher,
  80. \Magento\Framework\View\Asset\Repository $assetRepo,
  81. \Magento\Framework\Module\ModuleList $moduleList,
  82. \Magento\Framework\ObjectManagerInterface $objectManager,
  83. ConfigLoaderInterface $configLoader,
  84. DeploymentConfig $deploymentConfig = null
  85. ) {
  86. $this->state = $state;
  87. $this->response = $response;
  88. $this->request = $request;
  89. $this->publisher = $publisher;
  90. $this->assetRepo = $assetRepo;
  91. $this->moduleList = $moduleList;
  92. $this->objectManager = $objectManager;
  93. $this->configLoader = $configLoader;
  94. $this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class);
  95. }
  96. /**
  97. * Finds requested resource and provides it to the client
  98. *
  99. * @return \Magento\Framework\App\ResponseInterface
  100. * @throws \Exception
  101. */
  102. public function launch()
  103. {
  104. // disabling profiling when retrieving static resource
  105. \Magento\Framework\Profiler::reset();
  106. $appMode = $this->state->getMode();
  107. if ($appMode == \Magento\Framework\App\State::MODE_PRODUCTION
  108. && !$this->deploymentConfig->getConfigData(
  109. ConfigOptionsListConstants::CONFIG_PATH_SCD_ON_DEMAND_IN_PRODUCTION
  110. )
  111. ) {
  112. $this->response->setHttpResponseCode(404);
  113. } else {
  114. $path = $this->request->get('resource');
  115. $params = $this->parsePath($path);
  116. $this->state->setAreaCode($params['area']);
  117. $this->objectManager->configure($this->configLoader->load($params['area']));
  118. $file = $params['file'];
  119. unset($params['file']);
  120. $asset = $this->assetRepo->createAsset($file, $params);
  121. $this->response->setFilePath($asset->getSourceFile());
  122. $this->publisher->publish($asset);
  123. }
  124. return $this->response;
  125. }
  126. /**
  127. * @inheritdoc
  128. */
  129. public function catchException(Bootstrap $bootstrap, \Exception $exception)
  130. {
  131. $this->getLogger()->critical($exception->getMessage());
  132. if ($bootstrap->isDeveloperMode()) {
  133. $this->response->setHttpResponseCode(404);
  134. $this->response->setHeader('Content-Type', 'text/plain');
  135. $this->response->setBody(
  136. $exception->getMessage() . "\n" .
  137. Debug::trace(
  138. $exception->getTrace(),
  139. true,
  140. true,
  141. (bool)getenv('MAGE_DEBUG_SHOW_ARGS')
  142. )
  143. );
  144. $this->response->sendResponse();
  145. } else {
  146. require $this->getFilesystem()->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/404.php');
  147. }
  148. return true;
  149. }
  150. /**
  151. * Parse path to identify parts needed for searching original file
  152. *
  153. * @param string $path
  154. * @throws \InvalidArgumentException
  155. * @return array
  156. */
  157. protected function parsePath($path)
  158. {
  159. $path = ltrim($path, '/');
  160. $parts = explode('/', $path, 6);
  161. if (count($parts) < 5 || preg_match('/\.\.(\\\|\/)/', $path)) {
  162. //Checking that path contains all required parts and is not above static folder.
  163. throw new \InvalidArgumentException("Requested path '$path' is wrong.");
  164. }
  165. $result = [];
  166. $result['area'] = $parts[0];
  167. $result['theme'] = $parts[1] . '/' . $parts[2];
  168. $result['locale'] = $parts[3];
  169. if (count($parts) >= 6 && $this->moduleList->has($parts[4])) {
  170. $result['module'] = $parts[4];
  171. } else {
  172. $result['module'] = '';
  173. if (isset($parts[5])) {
  174. $parts[5] = $parts[4] . '/' . $parts[5];
  175. } else {
  176. $parts[5] = $parts[4];
  177. }
  178. }
  179. $result['file'] = $parts[5];
  180. return $result;
  181. }
  182. /**
  183. * Lazyload filesystem driver
  184. *
  185. * @deprecated 100.1.0
  186. * @return Filesystem
  187. */
  188. private function getFilesystem()
  189. {
  190. if (!$this->filesystem) {
  191. $this->filesystem = $this->objectManager->get(Filesystem::class);
  192. }
  193. return $this->filesystem;
  194. }
  195. /**
  196. * Retrieves LoggerInterface instance
  197. *
  198. * @return LoggerInterface
  199. * @deprecated 101.0.0
  200. */
  201. private function getLogger()
  202. {
  203. if (!$this->logger) {
  204. $this->logger = $this->objectManager->get(LoggerInterface::class);
  205. }
  206. return $this->logger;
  207. }
  208. }