Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Storage.php
Go to the documentation of this file.
1 <?php
7 
10 
22 {
23  const DIRECTORY_NAME_REGEXP = '/^[a-z0-9\-\_]+$/si';
24 
25  const THUMBS_DIRECTORY_NAME = '.thumbs';
26 
27  const THUMB_PLACEHOLDER_PATH_SUFFIX = 'Magento_Cms::images/placeholder_thumbnail.jpg';
28 
34  protected $_config;
35 
41  protected $_configAsArray;
42 
46  protected $_directory;
47 
51  protected $_imageFactory;
52 
56  protected $_assetRepo;
57 
63  protected $_coreFileStorageDb = null;
64 
70  protected $_cmsWysiwygImages = null;
71 
75  protected $_resizeParameters;
76 
80  protected $_extensions;
81 
85  protected $_dirs;
86 
90  protected $_backendUrl;
91 
95  protected $_session;
96 
103 
110 
117 
124 
130  protected $_uploaderFactory;
131 
154  public function __construct(
155  \Magento\Backend\Model\Session $session,
156  \Magento\Backend\Model\UrlInterface $backendUrl,
157  \Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages,
158  \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDb,
159  \Magento\Framework\Filesystem $filesystem,
160  \Magento\Framework\Image\AdapterFactory $imageFactory,
161  \Magento\Framework\View\Asset\Repository $assetRepo,
162  \Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory $storageCollectionFactory,
163  \Magento\MediaStorage\Model\File\Storage\FileFactory $storageFileFactory,
164  \Magento\MediaStorage\Model\File\Storage\DatabaseFactory $storageDatabaseFactory,
165  \Magento\MediaStorage\Model\File\Storage\Directory\DatabaseFactory $directoryDatabaseFactory,
166  \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
167  array $resizeParameters = [],
168  array $extensions = [],
169  array $dirs = [],
170  array $data = []
171  ) {
172  $this->_session = $session;
173  $this->_backendUrl = $backendUrl;
174  $this->_cmsWysiwygImages = $cmsWysiwygImages;
175  $this->_coreFileStorageDb = $coreFileStorageDb;
176  $this->_directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
177  $this->_imageFactory = $imageFactory;
178  $this->_assetRepo = $assetRepo;
179  $this->_storageCollectionFactory = $storageCollectionFactory;
180  $this->_storageFileFactory = $storageFileFactory;
181  $this->_storageDatabaseFactory = $storageDatabaseFactory;
182  $this->_directoryDatabaseFactory = $directoryDatabaseFactory;
183  $this->_uploaderFactory = $uploaderFactory;
184  $this->_resizeParameters = $resizeParameters;
185  $this->_extensions = $extensions;
186  $this->_dirs = $dirs;
187  parent::__construct($data);
188  }
189 
196  protected function createSubDirectories($path)
197  {
198  if ($this->_coreFileStorageDb->checkDbUsage()) {
200  $subDirectories = $this->_directoryDatabaseFactory->create();
201  $directories = $subDirectories->getSubdirectories($path);
202  foreach ($directories as $directory) {
203  $fullPath = rtrim($path, '/') . '/' . $directory['name'];
204  $this->_directory->create($fullPath);
205  }
206  }
207  }
208 
214  protected function getConditionsForExcludeDirs()
215  {
216  $conditions = ['reg_exp' => [], 'plain' => []];
217 
218  if ($this->_dirs['exclude']) {
219  foreach ($this->_dirs['exclude'] as $dir) {
220  $conditions[!empty($dir['regexp']) ? 'reg_exp' : 'plain'][$dir['name']] = true;
221  }
222  }
223 
224  // "include" section takes precedence and can revoke directory exclusion
225  if ($this->_dirs['include']) {
226  foreach ($this->_dirs['include'] as $dir) {
227  unset($conditions['reg_exp'][$dir['name']], $conditions['plain'][$dir['name']]);
228  }
229  }
230 
231  return $conditions;
232  }
233 
241  protected function removeItemFromCollection($collection, $conditions)
242  {
243  $regExp = $conditions['reg_exp'] ? '~' . implode('|', array_keys($conditions['reg_exp'])) . '~i' : null;
244  $storageRoot = $this->_cmsWysiwygImages->getStorageRoot();
245  $storageRootLength = strlen($storageRoot);
246 
247  foreach ($collection as $key => $value) {
248  $mediaSubPathname = substr($value->getFilename(), $storageRootLength);
249  $rootChildParts = explode('/', '/' . ltrim($mediaSubPathname, '/'));
250 
251  if (array_key_exists($rootChildParts[1], $conditions['plain'])
252  || ($regExp && preg_match($regExp, $value->getFilename()))) {
253  $collection->removeItemByKey($key);
254  }
255  }
256 
257  return $collection;
258  }
259 
266  public function getDirsCollection($path)
267  {
268  $this->createSubDirectories($path);
269 
270  $collection = $this->getCollection($path)
271  ->setCollectDirs(true)
272  ->setCollectFiles(false)
273  ->setCollectRecursively(false);
274 
275  $conditions = $this->getConditionsForExcludeDirs();
276 
277  return $this->removeItemFromCollection($collection, $conditions);
278  }
279 
287  public function getFilesCollection($path, $type = null)
288  {
289  if ($this->_coreFileStorageDb->checkDbUsage()) {
290  $files = $this->_storageDatabaseFactory->create()->getDirectoryFiles($path);
291 
293  $fileStorageModel = $this->_storageFileFactory->create();
294  foreach ($files as $file) {
295  $fileStorageModel->saveFile($file);
296  }
297  }
298 
299  $collection = $this->getCollection(
300  $path
301  )->setCollectDirs(
302  false
303  )->setCollectFiles(
304  true
305  )->setCollectRecursively(
306  false
307  )->setOrder(
308  'mtime',
309  \Magento\Framework\Data\Collection::SORT_ORDER_ASC
310  );
311 
312  // Add files extension filter
313  if ($allowed = $this->getAllowedExtensions($type)) {
314  $collection->setFilesFilter('/\.(' . implode('|', $allowed) . ')$/i');
315  }
316 
317  // prepare items
318  foreach ($collection as $item) {
319  $item->setId($this->_cmsWysiwygImages->idEncode($item->getBasename()));
320  $item->setName($item->getBasename());
321  $item->setShortName($this->_cmsWysiwygImages->getShortFilename($item->getBasename()));
322  $item->setUrl($this->_cmsWysiwygImages->getCurrentUrl() . $item->getBasename());
323  $item->setSize(filesize($item->getFilename()));
324  $item->setMimeType(\mime_content_type($item->getFilename()));
325 
326  if ($this->isImage($item->getBasename())) {
327  $thumbUrl = $this->getThumbnailUrl($item->getFilename(), true);
328  // generate thumbnail "on the fly" if it does not exists
329  if (!$thumbUrl) {
330  $thumbUrl = $this->_backendUrl->getUrl('cms/*/thumbnail', ['file' => $item->getId()]);
331  }
332 
333  $size = @getimagesize($item->getFilename());
334 
335  if (is_array($size)) {
336  $item->setWidth($size[0]);
337  $item->setHeight($size[1]);
338  }
339  } else {
340  $thumbUrl = $this->_assetRepo->getUrl(self::THUMB_PLACEHOLDER_PATH_SUFFIX);
341  }
342 
343  $item->setThumbUrl($thumbUrl);
344  }
345 
346  return $collection;
347  }
348 
355  public function getCollection($path = null)
356  {
358  $collection = $this->_storageCollectionFactory->create();
359  if ($path !== null) {
360  $collection->addTargetDir($path);
361  }
362  return $collection;
363  }
364 
373  public function createDirectory($name, $path)
374  {
375  if (!preg_match(self::DIRECTORY_NAME_REGEXP, $name)) {
376  throw new \Magento\Framework\Exception\LocalizedException(
377  __('Please rename the folder using only letters, numbers, underscores and dashes.')
378  );
379  }
380 
381  $relativePath = $this->_directory->getRelativePath($path);
382  if (!$this->_directory->isDirectory($relativePath) || !$this->_directory->isWritable($relativePath)) {
383  $path = $this->_cmsWysiwygImages->getStorageRoot();
384  }
385 
386  $newPath = $path . '/' . $name;
387  $relativeNewPath = $this->_directory->getRelativePath($newPath);
388  if ($this->_directory->isDirectory($relativeNewPath)) {
389  throw new \Magento\Framework\Exception\LocalizedException(
390  __('We found a directory with the same name. Please try another folder name.')
391  );
392  }
393 
394  $this->_directory->create($relativeNewPath);
395  try {
396  if ($this->_coreFileStorageDb->checkDbUsage()) {
397  $relativePath = $this->_coreFileStorageDb->getMediaRelativePath($newPath);
398  $this->_directoryDatabaseFactory->create()->createRecursive($relativePath);
399  }
400 
401  $result = [
402  'name' => $name,
403  'short_name' => $this->_cmsWysiwygImages->getShortFilename($name),
404  'path' => $newPath,
405  'id' => $this->_cmsWysiwygImages->convertPathToId($newPath),
406  ];
407  return $result;
408  } catch (\Magento\Framework\Exception\FileSystemException $e) {
409  throw new \Magento\Framework\Exception\LocalizedException(__('We cannot create a new directory.'));
410  }
411  }
412 
420  public function deleteDirectory($path)
421  {
422  if ($this->_coreFileStorageDb->checkDbUsage()) {
423  $this->_directoryDatabaseFactory->create()->deleteDirectory($path);
424  }
425  try {
426  $this->_deleteByPath($path);
427  $path = $this->getThumbnailRoot() . $this->_getRelativePathToRoot($path);
428  $this->_deleteByPath($path);
429  } catch (\Magento\Framework\Exception\FileSystemException $e) {
430  throw new \Magento\Framework\Exception\LocalizedException(__('We cannot delete directory %1.', $path));
431  }
432  }
433 
440  protected function _deleteByPath($path)
441  {
442  $path = $this->_sanitizePath($path);
443  if (!empty($path)) {
444  $this->_validatePath($path);
445  $this->_directory->delete($this->_directory->getRelativePath($path));
446  }
447  }
448 
455  public function deleteFile($target)
456  {
457  $relativePath = $this->_directory->getRelativePath($target);
458  if ($this->_directory->isFile($relativePath)) {
459  $this->_directory->delete($relativePath);
460  }
461  $this->_coreFileStorageDb->deleteFile($target);
462 
463  $thumb = $this->getThumbnailPath($target, true);
464  $relativePathThumb = $this->_directory->getRelativePath($thumb);
465  if ($thumb) {
466  if ($this->_directory->isFile($relativePathThumb)) {
467  $this->_directory->delete($relativePathThumb);
468  }
469  $this->_coreFileStorageDb->deleteFile($thumb);
470  }
471  return $this;
472  }
473 
482  public function uploadFile($targetPath, $type = null)
483  {
485  $uploader = $this->_uploaderFactory->create(['fileId' => 'image']);
486  $allowed = $this->getAllowedExtensions($type);
487  if ($allowed) {
488  $uploader->setAllowedExtensions($allowed);
489  }
490  $uploader->setAllowRenameFiles(true);
491  $uploader->setFilesDispersion(false);
492  if (!$uploader->checkMimeType($this->getAllowedMimeTypes($type))) {
493  throw new \Magento\Framework\Exception\LocalizedException(__('File validation failed.'));
494  }
495  $result = $uploader->save($targetPath);
496 
497  if (!$result) {
498  throw new \Magento\Framework\Exception\LocalizedException(__('We can\'t upload the file right now.'));
499  }
500 
501  // create thumbnail
502  $this->resizeFile($targetPath . '/' . $uploader->getUploadedFileName(), true);
503 
504  return $result;
505  }
506 
514  public function getThumbnailPath($filePath, $checkFile = false)
515  {
516  $mediaRootDir = $this->_cmsWysiwygImages->getStorageRoot();
517 
518  if (strpos($filePath, $mediaRootDir) === 0) {
519  $thumbPath = $this->getThumbnailRoot() . substr($filePath, strlen($mediaRootDir));
520 
521  if (!$checkFile || $this->_directory->isExist($this->_directory->getRelativePath($thumbPath))) {
522  return $thumbPath;
523  }
524  }
525 
526  return false;
527  }
528 
536  public function getThumbnailUrl($filePath, $checkFile = false)
537  {
538  $mediaRootDir = $this->_cmsWysiwygImages->getStorageRoot();
539 
540  if (strpos($filePath, $mediaRootDir) === 0) {
541  $thumbSuffix = self::THUMBS_DIRECTORY_NAME . substr($filePath, strlen($mediaRootDir));
542  if (!$checkFile || $this->_directory->isExist(
543  $this->_directory->getRelativePath($mediaRootDir . '/' . $thumbSuffix)
544  )
545  ) {
546  $thumbSuffix = substr(
547  $mediaRootDir,
548  strlen($this->_directory->getAbsolutePath())
549  ) . '/' . $thumbSuffix;
550  $randomIndex = '?rand=' . time();
551  return str_replace('\\', '/', $this->_cmsWysiwygImages->getBaseUrl() . $thumbSuffix) . $randomIndex;
552  }
553  }
554 
555  return false;
556  }
557 
565  public function resizeFile($source, $keepRatio = true)
566  {
567  $realPath = $this->_directory->getRelativePath($source);
568  if (!$this->_directory->isFile($realPath) || !$this->_directory->isExist($realPath)) {
569  return false;
570  }
571 
572  $targetDir = $this->getThumbsPath($source);
573  $pathTargetDir = $this->_directory->getRelativePath($targetDir);
574  if (!$this->_directory->isExist($pathTargetDir)) {
575  $this->_directory->create($pathTargetDir);
576  }
577  if (!$this->_directory->isExist($pathTargetDir)) {
578  return false;
579  }
580  $image = $this->_imageFactory->create();
581  $image->open($source);
582  $image->keepAspectRatio($keepRatio);
583  $image->resize($this->_resizeParameters['width'], $this->_resizeParameters['height']);
584  $dest = $targetDir . '/' . pathinfo($source, PATHINFO_BASENAME);
585  $image->save($dest);
586  if ($this->_directory->isFile($this->_directory->getRelativePath($dest))) {
587  return $dest;
588  }
589  return false;
590  }
591 
598  public function resizeOnTheFly($filename)
599  {
600  $path = $this->getSession()->getCurrentPath();
601  if (!$path) {
602  $path = $this->_cmsWysiwygImages->getCurrentPath();
603  }
604  return $this->resizeFile($path . '/' . $filename);
605  }
606 
613  public function getThumbsPath($filePath = false)
614  {
615  $mediaRootDir = $this->_cmsWysiwygImages->getStorageRoot();
616  $thumbnailDir = $this->getThumbnailRoot();
617 
618  if ($filePath && strpos($filePath, $mediaRootDir) === 0) {
619  $thumbnailDir .= dirname(substr($filePath, strlen($mediaRootDir)));
620  }
621 
622  return $thumbnailDir;
623  }
624 
630  public function getSession()
631  {
632  return $this->_session;
633  }
634 
641  public function getAllowedExtensions($type = null)
642  {
643  $allowed = $this->getExtensionsList($type);
644 
645  return array_keys(array_filter($allowed));
646  }
647 
653  public function getThumbnailRoot()
654  {
655  return $this->_cmsWysiwygImages->getStorageRoot() . '/' . self::THUMBS_DIRECTORY_NAME;
656  }
657 
664  public function isImage($filename)
665  {
666  if (!$this->hasData('_image_extensions')) {
667  $this->setData('_image_extensions', $this->getAllowedExtensions('image'));
668  }
669  $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
670  return in_array($ext, $this->_getData('_image_extensions'));
671  }
672 
678  public function getResizeWidth()
679  {
680  return $this->_resizeParameters['width'];
681  }
682 
688  public function getResizeHeight()
689  {
690  return $this->_resizeParameters['height'];
691  }
692 
698  public function getCmsWysiwygImages()
699  {
701  }
702 
710  protected function _validatePath($path)
711  {
712  $root = $this->_sanitizePath($this->_cmsWysiwygImages->getStorageRoot());
713  if ($root == $path) {
714  throw new \Magento\Framework\Exception\LocalizedException(
715  __('We can\'t delete root directory %1 right now.', $path)
716  );
717  }
718  if (strpos($path, $root) !== 0) {
719  throw new \Magento\Framework\Exception\LocalizedException(
720  __('Directory %1 is not under storage root path.', $path)
721  );
722  }
723  }
724 
731  protected function _sanitizePath($path)
732  {
733  return rtrim(preg_replace('~[/\\\]+~', '/', $this->_directory->getDriver()->getRealPathSafety($path)), '/');
734  }
735 
742  protected function _getRelativePathToRoot($path)
743  {
744  return substr(
745  $this->_sanitizePath($path),
746  strlen($this->_sanitizePath($this->_cmsWysiwygImages->getStorageRoot()))
747  );
748  }
749 
756  private function getAllowedMimeTypes($type = null): array
757  {
758  $allowed = $this->getExtensionsList($type);
759 
760  return array_values(array_filter($allowed));
761  }
762 
769  private function getExtensionsList($type = null): array
770  {
771  if (is_string($type) && array_key_exists("{$type}_allowed", $this->_extensions)) {
772  $allowed = $this->_extensions["{$type}_allowed"];
773  } else {
774  $allowed = $this->_extensions['allowed'];
775  }
776 
777  return $allowed;
778  }
779 }
__construct(\Magento\Backend\Model\Session $session, \Magento\Backend\Model\UrlInterface $backendUrl, \Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages, \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDb, \Magento\Framework\Filesystem $filesystem, \Magento\Framework\Image\AdapterFactory $imageFactory, \Magento\Framework\View\Asset\Repository $assetRepo, \Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory $storageCollectionFactory, \Magento\MediaStorage\Model\File\Storage\FileFactory $storageFileFactory, \Magento\MediaStorage\Model\File\Storage\DatabaseFactory $storageDatabaseFactory, \Magento\MediaStorage\Model\File\Storage\Directory\DatabaseFactory $directoryDatabaseFactory, \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory, array $resizeParameters=[], array $extensions=[], array $dirs=[], array $data=[])
Definition: Storage.php:154
$source
Definition: source.php:23
getThumbnailPath($filePath, $checkFile=false)
Definition: Storage.php:514
$target
Definition: skip.phtml:8
__()
Definition: __.php:13
$type
Definition: item.phtml:13
$value
Definition: gender.phtml:16
removeItemFromCollection($collection, $conditions)
Definition: Storage.php:241
resizeFile($source, $keepRatio=true)
Definition: Storage.php:565
getThumbnailUrl($filePath, $checkFile=false)
Definition: Storage.php:536
setData($key, $value=null)
Definition: DataObject.php:72
$relativePath
Definition: get.php:35
$filesystem
foreach($appDirs as $dir) $files
if(!isset($_GET['name'])) $name
Definition: log.php:14