Images.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Cms\Helper\Wysiwyg;
  7. use Magento\Framework\App\Filesystem\DirectoryList;
  8. /**
  9. * Wysiwyg Images Helper.
  10. */
  11. class Images extends \Magento\Framework\App\Helper\AbstractHelper
  12. {
  13. /**
  14. * Image directory subpath relative to media directory
  15. *
  16. * @var string
  17. */
  18. private $imageDirectorySubpath;
  19. /**
  20. * Current directory path
  21. * @var string
  22. */
  23. protected $_currentPath;
  24. /**
  25. * Current directory URL
  26. * @var string
  27. */
  28. protected $_currentUrl;
  29. /**
  30. * Currently selected store ID if applicable
  31. *
  32. * @var int
  33. */
  34. protected $_storeId;
  35. /**
  36. * @var \Magento\Framework\Filesystem\Directory\Write
  37. */
  38. protected $_directory;
  39. /**
  40. * Adminhtml data
  41. *
  42. * @var \Magento\Backend\Helper\Data
  43. */
  44. protected $_backendData;
  45. /**
  46. * Store manager
  47. *
  48. * @var \Magento\Store\Model\StoreManagerInterface
  49. */
  50. protected $_storeManager;
  51. /**
  52. * String escaper
  53. *
  54. * @var \Magento\Framework\Escaper
  55. */
  56. protected $escaper;
  57. /**
  58. * Construct
  59. *
  60. * @param \Magento\Framework\App\Helper\Context $context
  61. * @param \Magento\Backend\Helper\Data $backendData
  62. * @param \Magento\Framework\Filesystem $filesystem
  63. * @param \Magento\Store\Model\StoreManagerInterface $storeManager
  64. * @param \Magento\Framework\Escaper $escaper
  65. */
  66. public function __construct(
  67. \Magento\Framework\App\Helper\Context $context,
  68. \Magento\Backend\Helper\Data $backendData,
  69. \Magento\Framework\Filesystem $filesystem,
  70. \Magento\Store\Model\StoreManagerInterface $storeManager,
  71. \Magento\Framework\Escaper $escaper
  72. ) {
  73. parent::__construct($context);
  74. $this->_backendData = $backendData;
  75. $this->_storeManager = $storeManager;
  76. $this->escaper = $escaper;
  77. $this->_directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
  78. $this->_directory->create($this->getStorageRoot());
  79. }
  80. /**
  81. * Set a specified store ID value
  82. *
  83. * @param int $store
  84. * @return $this
  85. */
  86. public function setStoreId($store)
  87. {
  88. $this->_storeId = $store;
  89. return $this;
  90. }
  91. /**
  92. * Images Storage root directory
  93. *
  94. * @return string
  95. */
  96. public function getStorageRoot()
  97. {
  98. return $this->_directory->getAbsolutePath($this->getStorageRootSubpath());
  99. }
  100. /**
  101. * Get image storage root subpath. User is unable to traverse outside of this subpath in media gallery
  102. *
  103. * @return string
  104. */
  105. public function getStorageRootSubpath()
  106. {
  107. return '';
  108. }
  109. /**
  110. * Images Storage base URL
  111. *
  112. * @return string
  113. */
  114. public function getBaseUrl()
  115. {
  116. return $this->_storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
  117. }
  118. /**
  119. * Ext Tree node key name
  120. *
  121. * @return string
  122. */
  123. public function getTreeNodeName()
  124. {
  125. return 'node';
  126. }
  127. /**
  128. * Encode path to HTML element id
  129. *
  130. * @param string $path Path to file/directory
  131. * @return string
  132. */
  133. public function convertPathToId($path)
  134. {
  135. $path = str_replace($this->getStorageRoot(), '', $path);
  136. return $this->idEncode($path);
  137. }
  138. /**
  139. * Decode HTML element id.
  140. *
  141. * @param string $id
  142. * @return string
  143. * @throws \InvalidArgumentException When path contains restricted symbols.
  144. */
  145. public function convertIdToPath($id)
  146. {
  147. if ($id === \Magento\Theme\Helper\Storage::NODE_ROOT) {
  148. return $this->getStorageRoot();
  149. } else {
  150. $path = $this->getStorageRoot() . $this->idDecode($id);
  151. if (preg_match('/\.\.(\\\|\/)/', $path)) {
  152. throw new \InvalidArgumentException('Path is invalid');
  153. }
  154. return $path;
  155. }
  156. }
  157. /**
  158. * Check whether using static URLs is allowed
  159. *
  160. * @return bool
  161. */
  162. public function isUsingStaticUrlsAllowed()
  163. {
  164. $checkResult = (object) [];
  165. $checkResult->isAllowed = false;
  166. $this->_eventManager->dispatch(
  167. 'cms_wysiwyg_images_static_urls_allowed',
  168. ['result' => $checkResult, 'store_id' => $this->_storeId]
  169. );
  170. return $checkResult->isAllowed;
  171. }
  172. /**
  173. * Prepare Image insertion declaration for Wysiwyg or textarea(as_is mode)
  174. *
  175. * @param string $filename Filename transferred via Ajax
  176. * @param bool $renderAsTag Leave image HTML as is or transform it to controller directive
  177. * @return string
  178. */
  179. public function getImageHtmlDeclaration($filename, $renderAsTag = false)
  180. {
  181. $fileUrl = $this->getCurrentUrl() . $filename;
  182. $mediaUrl = $this->_storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
  183. $mediaPath = str_replace($mediaUrl, '', $fileUrl);
  184. $directive = sprintf('{{media url="%s"}}', $mediaPath);
  185. if ($renderAsTag) {
  186. $src = $this->isUsingStaticUrlsAllowed() ? $fileUrl : $this->escaper->escapeHtml($directive);
  187. $html = sprintf('<img src="%s" alt="" />', $src);
  188. } else {
  189. if ($this->isUsingStaticUrlsAllowed()) {
  190. $html = $fileUrl;
  191. } else {
  192. $directive = $this->urlEncoder->encode($directive);
  193. $html = $this->_backendData->getUrl(
  194. 'cms/wysiwyg/directive',
  195. [
  196. '___directive' => $directive,
  197. '_escape_params' => false,
  198. ]
  199. );
  200. }
  201. }
  202. return $html;
  203. }
  204. /**
  205. * Return path of the current selected directory or root directory for startup
  206. * Try to create target directory if it doesn't exist
  207. *
  208. * @return string
  209. * @throws \Magento\Framework\Exception\LocalizedException
  210. */
  211. public function getCurrentPath()
  212. {
  213. if (!$this->_currentPath) {
  214. $currentPath = $this->getStorageRoot();
  215. $path = $this->_getRequest()->getParam($this->getTreeNodeName());
  216. if ($path) {
  217. $path = $this->convertIdToPath($path);
  218. if ($this->_directory->isDirectory($this->_directory->getRelativePath($path))) {
  219. $currentPath = $path;
  220. }
  221. }
  222. try {
  223. $currentDir = $this->_directory->getRelativePath($currentPath);
  224. if (!$this->_directory->isExist($currentDir)) {
  225. $this->_directory->create($currentDir);
  226. }
  227. } catch (\Magento\Framework\Exception\FileSystemException $e) {
  228. $message = __('The directory %1 is not writable by server.', $currentPath);
  229. throw new \Magento\Framework\Exception\LocalizedException($message);
  230. }
  231. $this->_currentPath = $currentPath;
  232. }
  233. return $this->_currentPath;
  234. }
  235. /**
  236. * Return URL based on current selected directory or root directory for startup
  237. *
  238. * @return string
  239. */
  240. public function getCurrentUrl()
  241. {
  242. if (!$this->_currentUrl) {
  243. $path = $this->getCurrentPath();
  244. $mediaUrl = $this->_storeManager->getStore(
  245. $this->_storeId
  246. )->getBaseUrl(
  247. \Magento\Framework\UrlInterface::URL_TYPE_MEDIA
  248. );
  249. $this->_currentUrl = rtrim($mediaUrl . $this->_directory->getRelativePath($path), '/') . '/';
  250. }
  251. return $this->_currentUrl;
  252. }
  253. /**
  254. * Encode string to valid HTML id element, based on base64 encoding
  255. *
  256. * @param string $string
  257. * @return string
  258. */
  259. public function idEncode($string)
  260. {
  261. return strtr(base64_encode($string), '+/=', ':_-');
  262. }
  263. /**
  264. * Revert operation to idEncode
  265. *
  266. * @param string $string
  267. * @return string
  268. */
  269. public function idDecode($string)
  270. {
  271. $string = strtr($string, ':_-', '+/=');
  272. return base64_decode($string);
  273. }
  274. /**
  275. * Reduce filename by replacing some characters with dots
  276. *
  277. * @param string $filename
  278. * @param int $maxLength Maximum filename
  279. * @return string Truncated filename
  280. */
  281. public function getShortFilename($filename, $maxLength = 20)
  282. {
  283. if (strlen($filename) <= $maxLength) {
  284. return $filename;
  285. }
  286. return substr($filename, 0, $maxLength) . '...';
  287. }
  288. /**
  289. * Set user-traversable image directory subpath relative to media directory and relative to nested storage root
  290. *
  291. * @var string $subpath
  292. * @return void
  293. */
  294. public function setImageDirectorySubpath($subpath)
  295. {
  296. $this->imageDirectorySubpath = $subpath;
  297. }
  298. }