123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- <?php
- namespace Grav\Framework\Flex\Traits;
- /**
- * @package Grav\Framework\Flex
- *
- * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- use Grav\Common\Cache;
- use Grav\Common\Config\Config;
- use Grav\Common\Filesystem\Folder;
- use Grav\Common\Grav;
- use Grav\Common\Media\Interfaces\MediaCollectionInterface;
- use Grav\Common\Media\Traits\MediaTrait;
- use Grav\Common\Page\Medium\AbstractMedia;
- use Grav\Common\Page\Medium\Medium;
- use Grav\Common\Page\Medium\MediumFactory;
- use Grav\Common\Utils;
- use Grav\Framework\Flex\FlexDirectory;
- use Grav\Framework\Form\FormFlashFile;
- use Psr\Http\Message\UploadedFileInterface;
- use RocketTheme\Toolbox\File\YamlFile;
- use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
- use RuntimeException;
- /**
- * Implements Grav Page content and header manipulation methods.
- */
- trait FlexMediaTrait
- {
- use MediaTrait {
- MediaTrait::getMedia as protected getExistingMedia;
- }
- protected $_uploads;
- public function __debugInfo()
- {
- return parent::__debugInfo() + [
- 'uploads:private' => $this->getUpdatedMedia()
- ];
- }
- /**
- * @return string
- */
- public function getStorageFolder()
- {
- return $this->exists() ? $this->getFlexDirectory()->getStorageFolder($this->getStorageKey()) : '';
- }
- /**
- * @return string
- */
- public function getMediaFolder()
- {
- return $this->exists() ? $this->getFlexDirectory()->getMediaFolder($this->getStorageKey()) : '';
- }
- /**
- * @return MediaCollectionInterface
- */
- public function getMedia()
- {
- if ($this->media === null) {
- /** @var AbstractMedia $media */
- $media = $this->getExistingMedia();
- // Include uploaded media to the object media.
- /** @var FormFlashFile $upload */
- foreach ($this->getUpdatedMedia() as $filename => $upload) {
- // Just make sure we do not include removed or moved media.
- if ($upload && $upload->getError() === \UPLOAD_ERR_OK && !$upload->isMoved()) {
- $media->add($filename, MediumFactory::fromUploadedFile($upload));
- }
- }
- $media->setTimestamps();
- }
- return $this->media;
- }
- public function checkUploadedMediaFile(UploadedFileInterface $uploadedFile)
- {
- $grav = Grav::instance();
- $language = $grav['language'];
- switch ($uploadedFile->getError()) {
- case UPLOAD_ERR_OK:
- break;
- case UPLOAD_ERR_NO_FILE:
- if ($uploadedFile instanceof FormFlashFile) {
- break;
- }
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.NO_FILES_SENT'), 400);
- case UPLOAD_ERR_INI_SIZE:
- case UPLOAD_ERR_FORM_SIZE:
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.EXCEEDED_FILESIZE_LIMIT'), 400);
- case UPLOAD_ERR_NO_TMP_DIR:
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.UPLOAD_ERR_NO_TMP_DIR'), 400);
- default:
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.UNKNOWN_ERRORS'), 400);
- }
- $filename = $uploadedFile->getClientFilename();
- if (!Utils::checkFilename($filename)) {
- throw new RuntimeException(sprintf($language->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD'), $filename, 'Bad filename'), 400);
- }
- $grav_limit = Utils::getUploadLimit();
- if ($grav_limit > 0 && $uploadedFile->getSize() > $grav_limit) {
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.EXCEEDED_GRAV_FILESIZE_LIMIT'), 400);
- }
- $this->checkMediaFilename($filename);
- }
- public function checkMediaFilename(string $filename)
- {
- // Check the file extension.
- $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
- $grav = Grav::instance();
- /** @var Config $config */
- $config = $grav['config'];
- // If not a supported type, return
- if (!$extension || !$config->get("media.types.{$extension}")) {
- $language = $grav['language'];
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.UNSUPPORTED_FILE_TYPE') . ': ' . $extension, 400);
- }
- }
- public function uploadMediaFile(UploadedFileInterface $uploadedFile, string $filename = null): void
- {
- $this->checkUploadedMediaFile($uploadedFile);
- if ($filename) {
- $this->checkMediaFilename(basename($filename));
- } else {
- $filename = $uploadedFile->getClientFilename();
- }
- $media = $this->getMedia();
- $grav = Grav::instance();
- /** @var UniformResourceLocator $locator */
- $locator = $grav['locator'];
- $path = $media->getPath();
- if (!$path) {
- $language = $grav['language'];
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.FAILED_TO_MOVE_UPLOADED_FILE'), 400);
- }
- if ($locator->isStream($path)) {
- $path = $locator->findResource($path, true, true);
- $locator->clearCache($path);
- }
- try {
- // Upload it
- $filepath = sprintf('%s/%s', $path, $filename);
- Folder::create(\dirname($filepath));
- if ($uploadedFile instanceof FormFlashFile) {
- $metadata = $uploadedFile->getMetaData();
- if ($metadata) {
- $file = YamlFile::instance($filepath . '.meta.yaml');
- $file->save(['upload' => $metadata]);
- }
- if ($uploadedFile->getError() === \UPLOAD_ERR_OK) {
- $uploadedFile->moveTo($filepath);
- } elseif (!file_exists($filepath) && $pos = strpos($filename, '/')) {
- $origpath = sprintf('%s/%s', $path, substr($filename, $pos));
- if (file_exists($origpath)) {
- copy($origpath, $filepath);
- }
- }
- } else {
- $uploadedFile->moveTo($filepath);
- }
- } catch (\Exception $e) {
- $language = $grav['language'];
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.FAILED_TO_MOVE_UPLOADED_FILE'), 400);
- }
- $this->clearMediaCache();
- }
- public function deleteMediaFile(string $filename): void
- {
- $grav = Grav::instance();
- $language = $grav['language'];
- $basename = basename($filename);
- $dirname = dirname($filename);
- $dirname = $dirname === '.' ? '' : '/' . $dirname;
- if (!Utils::checkFilename($basename)) {
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': Bad filename: ' . $filename, 400);
- }
- $media = $this->getMedia();
- $path = $media->getPath();
- if (!$path) {
- return;
- }
- /** @var UniformResourceLocator $locator */
- $locator = $grav['locator'];
- $targetPath = $path . '/' . $dirname;
- $targetFile = $path . '/' . $filename;
- if ($locator->isStream($targetFile)) {
- $targetPath = $locator->findResource($targetPath, true, true);
- $targetFile = $locator->findResource($targetFile, true, true);
- $locator->clearCache($targetPath);
- $locator->clearCache($targetFile);
- }
- $fileParts = pathinfo($basename);
- if (!file_exists($targetPath)) {
- return;
- }
- if (file_exists($targetFile)) {
- $result = unlink($targetFile);
- if (!$result) {
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': ' . $filename, 500);
- }
- }
- // Remove Extra Files
- foreach (scandir($targetPath, SCANDIR_SORT_NONE) as $file) {
- $preg_name = preg_quote($fileParts['filename'], '`');
- $preg_ext =preg_quote($fileParts['extension'], '`');
- $preg_filename = preg_quote($basename, '`');
- if (preg_match("`({$preg_name}@\d+x\.{$preg_ext}(?:\.meta\.yaml)?$|{$preg_filename}\.meta\.yaml)$`", $file)) {
- $testPath = $targetPath . '/' . $file;
- if ($locator->isStream($testPath)) {
- $testPath = $locator->findResource($testPath, true, true);
- $locator->clearCache($testPath);
- }
- if (is_file($testPath)) {
- $result = unlink($testPath);
- if (!$result) {
- throw new RuntimeException($language->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': ' . $filename, 500);
- }
- }
- }
- }
- $this->clearMediaCache();
- }
- /**
- * @param array $files
- */
- protected function setUpdatedMedia(array $files): void
- {
- $list = [];
- foreach ($files as $field => $group) {
- if ($field === '' || \strpos($field, '/', true)) {
- continue;
- }
- foreach ($group as $filename => $file) {
- $list[$filename] = $file;
- }
- }
- $this->_uploads = $list;
- }
- /**
- * @return array
- */
- protected function getUpdatedMedia(): array
- {
- return $this->_uploads ?? [];
- }
- protected function saveUpdatedMedia(): void
- {
- /**
- * @var string $filename
- * @var UploadedFileInterface $file
- */
- foreach ($this->getUpdatedMedia() as $filename => $file) {
- if ($file) {
- $this->uploadMediaFile($file, $filename);
- } else {
- $this->deleteMediaFile($filename);
- }
- }
- $this->setUpdatedMedia([]);
- }
- /**
- * @param string $uri
- * @return Medium|null
- */
- protected function createMedium($uri)
- {
- $grav = Grav::instance();
- /** @var UniformResourceLocator $locator */
- $locator = $grav['locator'];
- $file = $uri && $locator->isStream($uri) ? $locator->findResource($uri) : $uri;
- return $file && file_exists($file) ? MediumFactory::fromFile($file) : null;
- }
- /**
- * @return Cache
- */
- protected function getMediaCache()
- {
- return $this->getCache('object');
- }
- protected function offsetLoad_media()
- {
- return $this->getMedia();
- }
- protected function offsetSerialize_media()
- {
- return null;
- }
- abstract public function getFlexDirectory(): FlexDirectory;
- abstract public function getStorageKey(): string;
- }
|