Http.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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\Debug;
  9. use Magento\Framework\ObjectManager\ConfigLoaderInterface;
  10. use Magento\Framework\App\Request\Http as RequestHttp;
  11. use Magento\Framework\App\Response\Http as ResponseHttp;
  12. use Magento\Framework\App\Response\HttpInterface;
  13. use Magento\Framework\Controller\ResultInterface;
  14. use Magento\Framework\Event;
  15. use Magento\Framework\Filesystem;
  16. /**
  17. * HTTP web application. Called from webroot index.php to serve web requests.
  18. *
  19. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  20. */
  21. class Http implements \Magento\Framework\AppInterface
  22. {
  23. /**
  24. * @var \Magento\Framework\ObjectManagerInterface
  25. */
  26. protected $_objectManager;
  27. /**
  28. * @var \Magento\Framework\Event\Manager
  29. */
  30. protected $_eventManager;
  31. /**
  32. * @var AreaList
  33. */
  34. protected $_areaList;
  35. /**
  36. * @var Request\Http
  37. */
  38. protected $_request;
  39. /**
  40. * @var ConfigLoaderInterface
  41. */
  42. protected $_configLoader;
  43. /**
  44. * @var State
  45. */
  46. protected $_state;
  47. /**
  48. * @var Filesystem
  49. */
  50. protected $_filesystem;
  51. /**
  52. * @var ResponseHttp
  53. */
  54. protected $_response;
  55. /**
  56. * @var \Magento\Framework\Registry
  57. */
  58. protected $registry;
  59. /**
  60. * @var \Psr\Log\LoggerInterface
  61. */
  62. private $logger;
  63. /**
  64. * @param \Magento\Framework\ObjectManagerInterface $objectManager
  65. * @param Event\Manager $eventManager
  66. * @param AreaList $areaList
  67. * @param RequestHttp $request
  68. * @param ResponseHttp $response
  69. * @param ConfigLoaderInterface $configLoader
  70. * @param State $state
  71. * @param Filesystem $filesystem
  72. * @param \Magento\Framework\Registry $registry
  73. */
  74. public function __construct(
  75. \Magento\Framework\ObjectManagerInterface $objectManager,
  76. Event\Manager $eventManager,
  77. AreaList $areaList,
  78. RequestHttp $request,
  79. ResponseHttp $response,
  80. ConfigLoaderInterface $configLoader,
  81. State $state,
  82. Filesystem $filesystem,
  83. \Magento\Framework\Registry $registry
  84. ) {
  85. $this->_objectManager = $objectManager;
  86. $this->_eventManager = $eventManager;
  87. $this->_areaList = $areaList;
  88. $this->_request = $request;
  89. $this->_response = $response;
  90. $this->_configLoader = $configLoader;
  91. $this->_state = $state;
  92. $this->_filesystem = $filesystem;
  93. $this->registry = $registry;
  94. }
  95. /**
  96. * Add new dependency
  97. *
  98. * @return \Psr\Log\LoggerInterface
  99. *
  100. * @deprecated 100.1.0
  101. */
  102. private function getLogger()
  103. {
  104. if (!$this->logger instanceof \Psr\Log\LoggerInterface) {
  105. $this->logger = \Magento\Framework\App\ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class);
  106. }
  107. return $this->logger;
  108. }
  109. /**
  110. * Run application
  111. *
  112. * @throws \InvalidArgumentException
  113. * @return ResponseInterface
  114. */
  115. public function launch()
  116. {
  117. $areaCode = $this->_areaList->getCodeByFrontName($this->_request->getFrontName());
  118. $this->_state->setAreaCode($areaCode);
  119. $this->_objectManager->configure($this->_configLoader->load($areaCode));
  120. /** @var \Magento\Framework\App\FrontControllerInterface $frontController */
  121. $frontController = $this->_objectManager->get(\Magento\Framework\App\FrontControllerInterface::class);
  122. $result = $frontController->dispatch($this->_request);
  123. // TODO: Temporary solution until all controllers return ResultInterface (MAGETWO-28359)
  124. if ($result instanceof ResultInterface) {
  125. $this->registry->register('use_page_cache_plugin', true, true);
  126. $result->renderResult($this->_response);
  127. } elseif ($result instanceof HttpInterface) {
  128. $this->_response = $result;
  129. } else {
  130. throw new \InvalidArgumentException('Invalid return type');
  131. }
  132. // This event gives possibility to launch something before sending output (allow cookie setting)
  133. $eventParams = ['request' => $this->_request, 'response' => $this->_response];
  134. $this->_eventManager->dispatch('controller_front_send_response_before', $eventParams);
  135. return $this->_response;
  136. }
  137. /**
  138. * @inheritdoc
  139. */
  140. public function catchException(Bootstrap $bootstrap, \Exception $exception)
  141. {
  142. $result = $this->handleDeveloperMode($bootstrap, $exception)
  143. || $this->handleBootstrapErrors($bootstrap, $exception)
  144. || $this->handleSessionException($exception)
  145. || $this->handleInitException($exception)
  146. || $this->handleGenericReport($bootstrap, $exception);
  147. return $result;
  148. }
  149. /**
  150. * Error handler for developer mode
  151. *
  152. * @param Bootstrap $bootstrap
  153. * @param \Exception $exception
  154. * @return bool
  155. */
  156. private function handleDeveloperMode(Bootstrap $bootstrap, \Exception $exception)
  157. {
  158. if ($bootstrap->isDeveloperMode()) {
  159. if (Bootstrap::ERR_IS_INSTALLED == $bootstrap->getErrorCode()) {
  160. try {
  161. $this->redirectToSetup($bootstrap, $exception);
  162. return true;
  163. } catch (\Exception $e) {
  164. $exception = $e;
  165. }
  166. }
  167. $this->_response->setHttpResponseCode(500);
  168. $this->_response->setHeader('Content-Type', 'text/plain');
  169. $this->_response->setBody($this->buildContentFromException($exception));
  170. $this->_response->sendResponse();
  171. return true;
  172. }
  173. return false;
  174. }
  175. /**
  176. * Build content based on an exception
  177. *
  178. * @param \Exception $exception
  179. * @return string
  180. */
  181. private function buildContentFromException(\Exception $exception)
  182. {
  183. /** @var \Exception[] $exceptions */
  184. $exceptions = [];
  185. do {
  186. $exceptions[] = $exception;
  187. } while ($exception = $exception->getPrevious());
  188. $buffer = sprintf("%d exception(s):\n", count($exceptions));
  189. foreach ($exceptions as $index => $exception) {
  190. $buffer .= sprintf("Exception #%d (%s): %s\n", $index, get_class($exception), $exception->getMessage());
  191. }
  192. foreach ($exceptions as $index => $exception) {
  193. $buffer .= sprintf(
  194. "\nException #%d (%s): %s\n%s\n",
  195. $index,
  196. get_class($exception),
  197. $exception->getMessage(),
  198. Debug::trace(
  199. $exception->getTrace(),
  200. true,
  201. true,
  202. (bool)getenv('MAGE_DEBUG_SHOW_ARGS')
  203. )
  204. );
  205. }
  206. return $buffer;
  207. }
  208. /**
  209. * If not installed, try to redirect to installation wizard
  210. *
  211. * @param Bootstrap $bootstrap
  212. * @param \Exception $exception
  213. * @return void
  214. * @throws \Exception
  215. */
  216. private function redirectToSetup(Bootstrap $bootstrap, \Exception $exception)
  217. {
  218. $setupInfo = new SetupInfo($bootstrap->getParams());
  219. $projectRoot = $this->_filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath();
  220. if ($setupInfo->isAvailable()) {
  221. $this->_response->setRedirect($setupInfo->getUrl());
  222. $this->_response->sendHeaders();
  223. } else {
  224. $newMessage = $exception->getMessage() . "\nNOTE: You cannot install Magento using the Setup Wizard "
  225. . "because the Magento setup directory cannot be accessed. \n"
  226. . 'You can install Magento using either the command line or you must restore access '
  227. . 'to the following directory: ' . $setupInfo->getDir($projectRoot) . "\n";
  228. throw new \Exception($newMessage, 0, $exception);
  229. }
  230. }
  231. /**
  232. * Handler for bootstrap errors
  233. *
  234. * @param Bootstrap $bootstrap
  235. * @param \Exception &$exception
  236. * @return bool
  237. */
  238. private function handleBootstrapErrors(Bootstrap $bootstrap, \Exception &$exception)
  239. {
  240. $bootstrapCode = $bootstrap->getErrorCode();
  241. if (Bootstrap::ERR_MAINTENANCE == $bootstrapCode) {
  242. require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/503.php');
  243. return true;
  244. }
  245. if (Bootstrap::ERR_IS_INSTALLED == $bootstrapCode) {
  246. try {
  247. $this->redirectToSetup($bootstrap, $exception);
  248. return true;
  249. } catch (\Exception $e) {
  250. $exception = $e;
  251. }
  252. }
  253. return false;
  254. }
  255. /**
  256. * Handler for session errors
  257. *
  258. * @param \Exception $exception
  259. * @return bool
  260. */
  261. private function handleSessionException(\Exception $exception)
  262. {
  263. if ($exception instanceof \Magento\Framework\Exception\SessionException) {
  264. $this->_response->setRedirect($this->_request->getDistroBaseUrl());
  265. $this->_response->sendHeaders();
  266. return true;
  267. }
  268. return false;
  269. }
  270. /**
  271. * Handler for application initialization errors
  272. *
  273. * @param \Exception $exception
  274. * @return bool
  275. */
  276. private function handleInitException(\Exception $exception)
  277. {
  278. if ($exception instanceof \Magento\Framework\Exception\State\InitException) {
  279. $this->getLogger()->critical($exception);
  280. require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/404.php');
  281. return true;
  282. }
  283. return false;
  284. }
  285. /**
  286. * Handle for any other errors
  287. *
  288. * @param Bootstrap $bootstrap
  289. * @param \Exception $exception
  290. * @return bool
  291. */
  292. private function handleGenericReport(Bootstrap $bootstrap, \Exception $exception)
  293. {
  294. $reportData = [
  295. $exception->getMessage(),
  296. Debug::trace(
  297. $exception->getTrace(),
  298. true,
  299. true,
  300. (bool)getenv('MAGE_DEBUG_SHOW_ARGS')
  301. )
  302. ];
  303. $params = $bootstrap->getParams();
  304. if (isset($params['REQUEST_URI'])) {
  305. $reportData['url'] = $params['REQUEST_URI'];
  306. }
  307. if (isset($params['SCRIPT_NAME'])) {
  308. $reportData['script_name'] = $params['SCRIPT_NAME'];
  309. }
  310. require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/report.php');
  311. return true;
  312. }
  313. }