vendor/pimcore/pimcore/bundles/CoreBundle/Controller/PublicServicesController.php line 184

Open in your IDE?
  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. namespace Pimcore\Bundle\CoreBundle\Controller;
  15. use function date;
  16. use function fstat;
  17. use function is_array;
  18. use Pimcore\Config;
  19. use Pimcore\Controller\Controller;
  20. use Pimcore\File;
  21. use Pimcore\Logger;
  22. use Pimcore\Model\Asset;
  23. use Pimcore\Model\Site;
  24. use Pimcore\Model\Tool\TmpStore;
  25. use Pimcore\Tool\Storage;
  26. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  27. use Symfony\Component\HttpFoundation\Cookie;
  28. use Symfony\Component\HttpFoundation\RedirectResponse;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\Response;
  31. use Symfony\Component\HttpFoundation\StreamedResponse;
  32. use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
  33. use function time;
  34. /**
  35. * @internal
  36. */
  37. class PublicServicesController extends Controller
  38. {
  39. /**
  40. * @param Request $request
  41. *
  42. * @return BinaryFileResponse|StreamedResponse
  43. */
  44. public function thumbnailAction(Request $request)
  45. {
  46. $assetId = $request->get('assetId');
  47. $thumbnailName = $request->get('thumbnailName');
  48. $filename = $request->get('filename');
  49. $requestedFileExtension = strtolower(File::getFileExtension($filename));
  50. $asset = Asset::getById($assetId);
  51. $prefix = preg_replace('@^cache-buster\-[\d]+\/@', '', $request->get('prefix'));
  52. if ($asset && $asset->getPath() === ('/' . $prefix)) {
  53. // we need to check the path as well, this is important in the case you have restricted the public access to
  54. // assets via rewrite rules
  55. try {
  56. $imageThumbnail = null;
  57. $thumbnailStream = null;
  58. // just check if the thumbnail exists -> throws exception otherwise
  59. $thumbnailConfig = Asset\Image\Thumbnail\Config::getByName($thumbnailName);
  60. if (!$thumbnailConfig) {
  61. // check if there's an item in the TmpStore
  62. // remove an eventually existing cache-buster prefix first (eg. when using with a CDN)
  63. $pathInfo = preg_replace('@^/cache-buster\-[\d]+@', '', $request->getPathInfo());
  64. $deferredConfigId = 'thumb_' . $assetId . '__' . md5(urldecode($pathInfo));
  65. if ($thumbnailConfigItem = TmpStore::get($deferredConfigId)) {
  66. $thumbnailConfig = $thumbnailConfigItem->getData();
  67. TmpStore::delete($deferredConfigId);
  68. if (!$thumbnailConfig instanceof Asset\Image\Thumbnail\Config) {
  69. throw new \Exception("Deferred thumbnail config file doesn't contain a valid \\Asset\\Image\\Thumbnail\\Config object");
  70. }
  71. }
  72. }
  73. if (!$thumbnailConfig) {
  74. throw $this->createNotFoundException("Thumbnail '" . $thumbnailName . "' file doesn't exist");
  75. }
  76. if (strcasecmp($thumbnailConfig->getFormat(), 'SOURCE') === 0) {
  77. $formatOverride = $requestedFileExtension;
  78. if (in_array($requestedFileExtension, ['jpg', 'jpeg'])) {
  79. $formatOverride = 'pjpeg';
  80. }
  81. $thumbnailConfig->setFormat($formatOverride);
  82. }
  83. if ($asset instanceof Asset\Video) {
  84. $time = 1;
  85. if (preg_match("|~\-~time\-(\d+)\.|", $filename, $matchesThumbs)) {
  86. $time = (int)$matchesThumbs[1];
  87. }
  88. $imageThumbnail = $asset->getImageThumbnail($thumbnailConfig, $time);
  89. $thumbnailStream = $imageThumbnail->getStream();
  90. } elseif ($asset instanceof Asset\Document) {
  91. $page = 1;
  92. if (preg_match("|~\-~page\-(\d+)\.|", $filename, $matchesThumbs)) {
  93. $page = (int)$matchesThumbs[1];
  94. }
  95. $thumbnailConfig->setName(preg_replace("/\-[\d]+/", '', $thumbnailConfig->getName()));
  96. $thumbnailConfig->setName(str_replace('document_', '', $thumbnailConfig->getName()));
  97. $imageThumbnail = $asset->getImageThumbnail($thumbnailConfig, $page);
  98. $thumbnailStream = $imageThumbnail->getStream();
  99. } elseif ($asset instanceof Asset\Image) {
  100. //check if high res image is called
  101. preg_match("@([^\@]+)(\@[0-9.]+x)?\.([a-zA-Z]{2,5})@", $filename, $matches);
  102. if (array_key_exists(2, $matches) && $matches[2]) {
  103. $highResFactor = (float) str_replace(['@', 'x'], '', $matches[2]);
  104. $thumbnailConfig->setHighResolution($highResFactor);
  105. }
  106. // check if a media query thumbnail was requested
  107. if (preg_match("#~\-~media\-\-(.*)\-\-query#", $matches[1], $mediaQueryResult)) {
  108. $thumbnailConfig->selectMedia($mediaQueryResult[1]);
  109. }
  110. $imageThumbnail = $asset->getThumbnail($thumbnailConfig);
  111. $thumbnailStream = $imageThumbnail->getStream();
  112. }
  113. if ($imageThumbnail && $thumbnailStream) {
  114. $pathReference = $imageThumbnail->getPathReference();
  115. $actualFileExtension = File::getFileExtension($pathReference['src']);
  116. if ($actualFileExtension !== $requestedFileExtension) {
  117. // create a copy/symlink to the file with the original file extension
  118. // this can be e.g. the case when the thumbnail is called as foo.png but the thumbnail config
  119. // is set to auto-optimized format so the resulting thumbnail can be jpeg
  120. $requestedFile = preg_replace('/\.' . $actualFileExtension . '$/', '.' . $requestedFileExtension, $pathReference['src']);
  121. Storage::get('thumbnail')->writeStream($requestedFile, $thumbnailStream);
  122. }
  123. // set appropriate caching headers
  124. // see also: https://github.com/pimcore/pimcore/blob/1931860f0aea27de57e79313b2eb212dcf69ef13/.htaccess#L86-L86
  125. $lifetime = 86400 * 7; // 1 week lifetime, same as direct delivery in .htaccess
  126. $headers = [
  127. 'Cache-Control' => 'public, max-age=' . $lifetime,
  128. 'Expires' => date('D, d M Y H:i:s T', time() + $lifetime),
  129. 'Content-Type' => $imageThumbnail->getMimeType(),
  130. ];
  131. $stats = fstat($thumbnailStream);
  132. if (is_array($stats)) {
  133. $headers['Content-Length'] = $stats['size'];
  134. }
  135. $headers[AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER] = true;
  136. return new StreamedResponse(function () use ($thumbnailStream) {
  137. fpassthru($thumbnailStream);
  138. }, 200, $headers);
  139. }
  140. throw new \Exception('Unable to generate thumbnail, see logs for details.');
  141. } catch (\Exception $e) {
  142. $message = "Thumbnail with name '" . $thumbnailName . "' doesn't exist";
  143. Logger::error($message);
  144. return new BinaryFileResponse(PIMCORE_WEB_ROOT . '/bundles/pimcoreadmin/img/filetype-not-supported.svg', 200);
  145. }
  146. }
  147. throw $this->createNotFoundException('Asset not found');
  148. }
  149. /**
  150. * @param Request $request
  151. *
  152. * @return Response
  153. */
  154. public function robotsTxtAction(Request $request)
  155. {
  156. // check for site
  157. $domain = \Pimcore\Tool::getHostname();
  158. $site = Site::getByDomain($domain);
  159. $config = Config::getRobotsConfig()->toArray();
  160. $siteId = 'default';
  161. if ($site instanceof Site) {
  162. $siteId = $site->getId();
  163. }
  164. // send correct headers
  165. header('Content-Type: text/plain; charset=utf8');
  166. while (@ob_end_flush()) ;
  167. // check for configured robots.txt in pimcore
  168. $content = '';
  169. if (array_key_exists($siteId, $config)) {
  170. $content = $config[$siteId];
  171. }
  172. if (empty($content)) {
  173. // default behavior, allow robots to index everything
  174. $content = "User-agent: *\nDisallow:";
  175. }
  176. return new Response($content, Response::HTTP_OK, [
  177. 'Content-Type' => 'text/plain',
  178. ]);
  179. }
  180. /**
  181. * @param Request $request
  182. *
  183. * @return Response
  184. */
  185. public function commonFilesAction(Request $request)
  186. {
  187. return new Response("HTTP/1.1 404 Not Found\nFiltered by common files filter", 404);
  188. }
  189. /**
  190. * @param Request $request
  191. *
  192. * @return \Symfony\Component\HttpFoundation\RedirectResponse
  193. */
  194. public function customAdminEntryPointAction(Request $request)
  195. {
  196. $params = $request->query->all();
  197. if (isset($params['token'])) {
  198. $url = $this->generateUrl('pimcore_admin_login_check', $params);
  199. } else {
  200. $url = $this->generateUrl('pimcore_admin_login', $params);
  201. }
  202. $redirect = new RedirectResponse($url);
  203. $customAdminPathIdentifier = $this->getParameter('pimcore_admin.custom_admin_path_identifier');
  204. if (!empty($customAdminPathIdentifier) && $request->cookies->get('pimcore_custom_admin') != $customAdminPathIdentifier) {
  205. $redirect->headers->setCookie(new Cookie('pimcore_custom_admin', $customAdminPathIdentifier, strtotime('+1 year'), '/', null, false, true));
  206. }
  207. return $redirect;
  208. }
  209. }