_isRevsliderModule = $request->getParam('module') == 'revslider'; if ($this->_isRevsliderModule) { $extendExtensions = [ 'allowed' => [ 'webp' => 'image/webp' ], 'image_allowed' => [ 'webp' => 'image/webp' ], 'video_allowed' => [ 'mp4' => 1, 'mp3' => 1, 'webm' => 1, 'ogv' => 1, 'avi' => 1 ] ]; foreach ($extendExtensions as $key => $value) { $extendedExtensions[$key] = array_merge(isset($extensions[$key]) ? $extensions[$key] : [], $value); } $extensions = $extendedExtensions; } parent::__construct( $session, $backendUrl, $cmsWysiwygImages, $coreFileStorageDb, $filesystem, $imageFactory, $assetRepo, $storageCollectionFactory, $storageFileFactory, $storageDatabaseFactory, $directoryDatabaseFactory, $uploaderFactory, $resizeParameters, $extensions, $dirs, $data ); $this->coreConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class); $this->logger = ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class); $this->file = ObjectManager::getInstance()->get(\Magento\Framework\Filesystem\Driver\File::class); $this->ioFile = ObjectManager::getInstance()->get(\Magento\Framework\Filesystem\Io\File::class); $this->mime = ObjectManager::getInstance()->get(\Magento\Framework\File\Mime::class); // Check if we are on legacy version $reflectionClass = new \ReflectionClass(WysiwygImagesStorage::class); try { $reflectionClass->getMethod('getAllowedMimeTypes'); } catch (\Exception $e) { Data::log('Legacy 2.1.x code detected', $e->getMessage()); $this->_isLegacy21x = true; } try { $reflectionClass->getMethod('isDirectoryAllowed'); } catch (\Exception $e) { Data::log('Legacy 2.2.x code detected', $e->getMessage()); $this->_isLegacy22x = true; } } /** * Return one-level child directories for specified path * * @param string $path Parent directory path * @return \Magento\Framework\Data\Collection\Filesystem * @throws \Exception */ public function getDirsCollection($path) { $this->createSubDirectories($path); $collection = $this->getCollection($path) ->setCollectDirs(true) ->setCollectFiles(false) ->setCollectRecursively(false) ->setOrder('basename', \Magento\Framework\Data\Collection\Filesystem::SORT_ORDER_ASC); if (!$this->isDirectoryAllowed($path)) { $collection->setDirsFilter($this->getAllowedDirMask($path)); } return $collection; } /** * Return files * * @param string $path Parent directory path * @param string $type Type of storage, e.g. image, media etc. * @return \Magento\Framework\Data\Collection\Filesystem * * @throws \Magento\Framework\Exception\FileSystemException * @throws \Magento\Framework\Exception\LocalizedException */ public function getFilesCollection($path, $type = null) { $collectFiles = $this->isDirectoryAllowed($path); if ($this->_coreFileStorageDb->checkDbUsage()) { $files = $this->_storageDatabaseFactory->create()->getDirectoryFiles($path); /** @var \Magento\MediaStorage\Model\File\Storage\File $fileStorageModel */ $fileStorageModel = $this->_storageFileFactory->create(); foreach ($files as $file) { $fileStorageModel->saveFile($file); } } $collection = $this->getCollection( $path )->setCollectDirs( false )->setCollectFiles( $collectFiles )->setCollectRecursively( false )->setOrder( 'mtime', \Magento\Framework\Data\Collection::SORT_ORDER_ASC ); // Add files extension filter if ($allowed = $this->getAllowedExtensions($type)) { $collection->setFilesFilter('/\.(' . implode('|', $allowed) . ')$/i'); } foreach ($collection as $item) { $item->setId($this->_cmsWysiwygImages->idEncode($item->getBasename())); $item->setName($item->getBasename()); $item->setShortName($this->_cmsWysiwygImages->getShortFilename($item->getBasename())); $item->setUrl($this->_cmsWysiwygImages->getCurrentUrl() . $item->getBasename()); $driver = $this->_directory->getDriver(); $itemStats = $driver->stat($item->getFilename()); $item->setSize($itemStats['size']); $mimeType = $itemStats['mimetype'] ?? $this->mime->getMimeType($item->getFilename()); $item->setMimeType($mimeType); if ($this->isImage($item->getBasename())) { $thumbUrl = $this->getThumbnailUrl($item->getFilename(), true); // generate thumbnail "on the fly" if it does not exists if (!$thumbUrl) { $thumbOptions = [ 'file' => $item->getId(), ]; if ($this->_isRevsliderModule) { $thumbOptions['module'] = 'revslider'; } $thumbUrl = $this->_backendUrl->getUrl('cms/*/thumbnail', $thumbOptions); } try { $size = getimagesizefromstring( $driver->fileGetContents($item->getFilename()) ); if (is_array($size)) { $item->setWidth($size[0]); $item->setHeight($size[1]); } } catch (\Error $e) { $this->logger->notice(sprintf("GetImageSize caused error: %s", $e->getMessage())); } } else { $thumbUrl = $this->_assetRepo->getUrl(self::THUMB_PLACEHOLDER_PATH_SUFFIX); } $item->setThumbUrl($thumbUrl); } return $collection; } /** * Create new directory in storage * * @param string $name New directory name * @param string $path Parent directory path * @return array New directory info * @throws \Magento\Framework\Exception\LocalizedException */ public function createDirectory($name, $path) { if (!preg_match(self::DIRECTORY_NAME_REGEXP, $name)) { throw new \Magento\Framework\Exception\LocalizedException( __('Please rename the folder using only Latin letters, numbers, underscores and dashes.') ); } if (!($this->isDirectoryAllowed(rtrim($path, '/') . '/' . $name))) { throw new \Magento\Framework\Exception\LocalizedException( __('We cannot create the folder under the selected directory.') ); } $relativePath = (string) $this->_directory->getRelativePath($path); if (!$this->_directory->isDirectory($relativePath) || !$this->_directory->isWritable($relativePath)) { $path = $this->_cmsWysiwygImages->getStorageRoot(); } $newPath = rtrim($path, '/') . '/' . $name; $relativeNewPath = $this->_directory->getRelativePath($newPath); if ($this->_directory->isDirectory($relativeNewPath)) { throw new \Magento\Framework\Exception\LocalizedException( __('We found a directory with the same name. Please try another folder name.') ); } $this->_directory->create($relativeNewPath); try { if ($this->_coreFileStorageDb->checkDbUsage()) { $relativePath = $this->_coreFileStorageDb->getMediaRelativePath($newPath); $this->_directoryDatabaseFactory->create()->createRecursive($relativePath); } $result = [ 'name' => $name, 'short_name' => $this->_cmsWysiwygImages->getShortFilename($name), 'path' => $newPath, 'id' => $this->_cmsWysiwygImages->convertPathToId($newPath), ]; return $result; } catch (\Magento\Framework\Exception\FileSystemException $e) { throw new \Magento\Framework\Exception\LocalizedException(__('We cannot create a new directory.')); } } /** * Recursively delete directory from storage * * @param string $path Absolute path to target directory * @return void * @throws \Magento\Framework\Exception\LocalizedException */ public function deleteDirectory($path) { if (!$this->isDirectoryAllowed(dirname($path))) { throw new \Magento\Framework\Exception\LocalizedException( __('We cannot delete the selected directory.') ); } if ($this->_coreFileStorageDb->checkDbUsage()) { $this->_directoryDatabaseFactory->create()->deleteDirectory($path); } try { $this->_deleteByPath($path); $path = $this->getThumbnailRoot() . $this->_getRelativePathToRoot($path); $this->_deleteByPath($path); } catch (\Magento\Framework\Exception\FileSystemException $e) { throw new \Magento\Framework\Exception\LocalizedException( __('We cannot delete directory %1.', $this->_getRelativePathToRoot($path)) ); } } /** * Delete file (and its thumbnail if exists) from storage * * @param string $target File path to be deleted * @return $this * @throws \Magento\Framework\Exception\FileSystemException * @throws \Magento\Framework\Exception\ValidatorException */ public function deleteFile($target) { if (!$this->isDirectoryAllowed(dirname($target))) { throw new \Magento\Framework\Exception\LocalizedException( __('We can\'t delete the file right now.') ); } $relativePath = $this->_directory->getRelativePath($target); if ($this->_directory->isFile($relativePath)) { $this->_directory->delete($relativePath); } $this->_coreFileStorageDb->deleteFile($target); $thumb = $this->getThumbnailPath($target, true); $relativePathThumb = $this->_directory->getRelativePath($thumb); if ($thumb) { if ($this->_directory->isFile($relativePathThumb)) { $this->_directory->delete($relativePathThumb); } $this->_coreFileStorageDb->deleteFile($thumb); } return $this; } /** * Upload and resize new file * * @param string $targetPath Target directory * @param string $type Type of storage, e.g. image, media etc. * @return array File info Array * @throws \Magento\Framework\Exception\LocalizedException */ public function uploadFile($targetPath, $type = null) { if (!($this->isDirectoryAllowed($targetPath))) { throw new \Magento\Framework\Exception\LocalizedException( __('We can\'t upload the file to the current folder right now. Please try another folder.') ); } /** @var \Magento\MediaStorage\Model\File\Uploader $uploader */ $uploader = $this->_uploaderFactory->create(['fileId' => 'image']); $allowed = $this->getAllowedExtensions($type); if ($allowed) { $uploader->setAllowedExtensions($allowed); } $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); if (! $this->_isLegacy21x && !$uploader->checkMimeType($this->getAllowedMimeTypes($type))) { throw new \Magento\Framework\Exception\LocalizedException(__('File validation failed.')); } $result = $uploader->save($targetPath); if (!$result) { throw new \Magento\Framework\Exception\LocalizedException(__('We can\'t upload the file right now.')); } // create thumbnail if ($type != 'video') { $this->resizeFile(rtrim($targetPath, '/') . '/' . ltrim($uploader->getUploadedFileName(), '/'), true); } return $result; } /** * Prepare mime types config settings. * * @param string|null $type Type of storage, e.g. image, media etc. * @return array Array of allowed file extensions */ private function getAllowedMimeTypes($type = null): array { $allowed = $this->getExtensionsList($type); if ($type == 'video') { $allowed = array_keys(array_filter($allowed)); foreach ($allowed as $key => $item) { $allowed[$key] = $type . '/' . $item; } } else { $allowed = array_values(array_filter($allowed)); } return $allowed; } /** * Get list of allowed file extensions with mime type in values. * * @param string|null $type * @return array */ private function getExtensionsList($type = null): array { if (is_string($type) && array_key_exists("{$type}_allowed", $this->_extensions)) { $allowed = $this->_extensions["{$type}_allowed"]; } else { $allowed = $this->_extensions['allowed']; } return $allowed; } /** * Check if directory is allowed * * @param string $directoryPath Absolute path to a directory * @return bool */ private function isDirectoryAllowed($directoryPath): bool { if ($this->_isRevsliderModule) { // revslider module $storageRoot = $this->_cmsWysiwygImages->getStorageRoot(); $storageRootLength = strlen($storageRoot) - strlen(Images::IMAGE_DIR); $mediaSubPathname = substr($directoryPath, $storageRootLength); if (!$mediaSubPathname) { return false; } $mediaSubPathname = ltrim($mediaSubPathname, '/'); return strpos($mediaSubPathname, Images::IMAGE_DIR) === 0; } elseif ($this->_isLegacy22x) { // no such method in older version so just allow it return true; } else { // original code $storageRoot = $this->_cmsWysiwygImages->getStorageRoot(); $storageRootLength = strlen($storageRoot); $mediaSubPathname = $directoryPath === null ? '' : substr($directoryPath, $storageRootLength); if (!$mediaSubPathname) { return false; } $mediaSubPathname = ltrim($mediaSubPathname, '/'); return preg_match($this->getAllowedPathPattern(), $mediaSubPathname) == 1; } } /** * Get allowed path pattern * * @return string */ private function getAllowedPathPattern() { if (null === $this->allowedPathPattern) { $mediaGalleryImageFolders = $this->coreConfig->getValue( self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, 'default' ); $regExp = '/^('; $or = ''; foreach ($mediaGalleryImageFolders as $folder) { $folderPattern = str_replace('/', '[\/]+', $folder ?? ''); $regExp .= $or . $folderPattern . '\b(?!-)(?:\/?[a-zA-Z0-9\-\_]+)*\/?$'; $or = '|'; } $regExp .= ')/'; $this->allowedPathPattern = $regExp; } return $this->allowedPathPattern; } }