Files
figureslibres.cc/system/src/Grav/Framework/Flex/Traits/FlexMediaTrait.php
T
2020-09-08 11:32:48 +02:00

347 lines
11 KiB
PHP

<?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;
}