mirror of
https://github.com/jbcr/core.git
synced 2026-04-26 01:58:15 +02:00
Working on file uploader
This commit is contained in:
@@ -93,11 +93,12 @@ class Config
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param bool $absolute
|
||||
* @param bool $absolute
|
||||
* @param mixed $additional
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath(string $path, bool $absolute = true, string $additional = ''): string
|
||||
public function getPath(string $path, bool $absolute = true, $additional = null): string
|
||||
{
|
||||
return $this->pathResolver->resolve($path, $absolute, $additional);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bolt\Configuration;
|
||||
|
||||
use Exception;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
use Webmozart\PathUtil\Path;
|
||||
|
||||
@@ -92,12 +93,13 @@ class PathResolver
|
||||
* - `foo/bar` - A relative path that will be resolved against the root path.
|
||||
* - `/tmp` - An absolute path will be returned as is.
|
||||
*
|
||||
* @param string $path the path
|
||||
* @param bool $absolute if the path is relative, resolve it against the root path
|
||||
* @param string $path the path
|
||||
* @param bool $absolute if the path is relative, resolve it against the root path
|
||||
* @param mixed $additional
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function resolve(string $path, bool $absolute = true, string $additional = ''): string
|
||||
public function resolve(string $path, bool $absolute = true, $additional = null): string
|
||||
{
|
||||
if (isset($this->paths[$path])) {
|
||||
$path = $this->paths[$path];
|
||||
@@ -129,8 +131,8 @@ class PathResolver
|
||||
$path = Path::makeAbsolute($path, $this->paths['root']);
|
||||
}
|
||||
|
||||
if ($additional !== '') {
|
||||
$path .= '/' . $additional;
|
||||
if (!empty($additional)) {
|
||||
$path .= DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, (array) $additional);
|
||||
}
|
||||
|
||||
// Make sure we don't have lingering unneeded dir-seperators
|
||||
|
||||
@@ -7,14 +7,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bolt\Content;
|
||||
|
||||
use Bolt\Common\Json;
|
||||
use Bolt\Configuration\Config;
|
||||
use Bolt\Entity\Media;
|
||||
use Bolt\Media\Item;
|
||||
use Bolt\Repository\MediaRepository;
|
||||
use Carbon\Carbon;
|
||||
use Cocur\Slugify\Slugify;
|
||||
use Faker\Factory;
|
||||
use PHPExif\Reader\Reader;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
use Webmozart\PathUtil\Path;
|
||||
|
||||
class MediaFactory
|
||||
{
|
||||
@@ -116,4 +121,55 @@ class MediaFactory
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
* @param $params
|
||||
* @return Media
|
||||
*/
|
||||
public function createFromUpload(Item $item, $params): Media
|
||||
{
|
||||
if (Json::test($params)) {
|
||||
$params = Json::parse($params);
|
||||
$addedPath = $params['path'];
|
||||
$area = $params['area'];
|
||||
} else {
|
||||
$addedPath = '';
|
||||
$area = 'files';
|
||||
}
|
||||
|
||||
$targetFilename = $addedPath . DIRECTORY_SEPARATOR . $this->sanitiseFilename($item->getName());
|
||||
|
||||
$source = $this->config->getPath('cache', true, ['uploads', $item->getId(), $item->getName()]);
|
||||
$target = $this->config->getPath($area, true, $targetFilename);
|
||||
|
||||
$relPath = Path::getDirectory($targetFilename);
|
||||
$relName = Path::getFilename($targetFilename);
|
||||
|
||||
// Move the file over
|
||||
$fileSystem = new Filesystem();
|
||||
$fileSystem->rename($source, $target, true);
|
||||
|
||||
$file = new SplFileInfo($target, $relPath, $relName);
|
||||
|
||||
$media = $this->createOrUpdateMedia($file, $area);
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
private function sanitiseFilename(string $filename): string
|
||||
{
|
||||
$extensionSlug = new Slugify(['regexp' => '/([^a-z0-9]|-)+/']);
|
||||
$filenameSlug = new Slugify(['lowercase' => false]);
|
||||
|
||||
$extension = $extensionSlug->slugify(Path::getExtension($filename));
|
||||
$filename = $filenameSlug->slugify(Path::getFilenameWithoutExtension($filename));
|
||||
|
||||
return $filename . '.' . $extension;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Controller\Async;
|
||||
|
||||
use Bolt\Content\MediaFactory;
|
||||
use Bolt\Media\RequestHandler;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class Uploader
|
||||
{
|
||||
/** @var MediaFactory*/
|
||||
private $mediaFactory;
|
||||
|
||||
/** @var RequestHandler */
|
||||
private $requestHandler;
|
||||
|
||||
/** @var ObjectManager */
|
||||
private $manager;
|
||||
|
||||
public function __construct(MediaFactory $mediaFactory, RequestHandler $requestHandler, ObjectManager $manager)
|
||||
{
|
||||
$this->mediaFactory = $mediaFactory;
|
||||
$this->requestHandler = $requestHandler;
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route("/async/upload", name="bolt_upload_post", methods={"POST"})
|
||||
*
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
{
|
||||
// Get submitted field data item, will always be one item in case of async upload
|
||||
$items = $this->requestHandler->loadFilesByField('filepond');
|
||||
|
||||
// If no items, exit
|
||||
if (count($items) === 0) {
|
||||
// Something went wrong, most likely a field name mismatch
|
||||
http_response_code(400);
|
||||
return;
|
||||
}
|
||||
|
||||
$params = $request->request->get('filepond', []);
|
||||
|
||||
foreach($items as $item) {
|
||||
$media = $this->mediaFactory->createFromUpload($item, current($params));
|
||||
dump($media);
|
||||
|
||||
$this->manager->persist($media);
|
||||
$this->manager->flush();
|
||||
}
|
||||
|
||||
// Returns plain text content
|
||||
header('Content-Type: text/plain');
|
||||
|
||||
// Remove item from array Response contains uploaded file server id
|
||||
echo array_shift($items)->getId();
|
||||
|
||||
return new Response("Finis!");
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,14 @@ class EditRecordController extends BaseController
|
||||
/**
|
||||
* @Route("/edit/{id}", name="bolt_edit_record", methods={"GET"})
|
||||
*
|
||||
* @param string $id
|
||||
* @param Request $request
|
||||
* @param string $id
|
||||
* @param Request $request
|
||||
* @param Content|null $content
|
||||
*
|
||||
* @return Response
|
||||
* @throws \Twig_Error_Loader
|
||||
* @throws \Twig_Error_Runtime
|
||||
* @throws \Twig_Error_Syntax
|
||||
*/
|
||||
public function edit(string $id, Request $request, Content $content = null): Response
|
||||
{
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Media;
|
||||
|
||||
/**
|
||||
* A wrapper class for easier access to $_FILES object
|
||||
*/
|
||||
|
||||
class Item {
|
||||
|
||||
// counter that helps in ensuring each file receives a truly unique id
|
||||
public static $item_counter = 0;
|
||||
|
||||
// item props
|
||||
private $id;
|
||||
private $file;
|
||||
private $name;
|
||||
|
||||
public function __construct($file, $id = null) {
|
||||
$this->id = isset($id) ? $id : md5( uniqid(self::$item_counter++, true) );
|
||||
$this->file = $file;
|
||||
$this->name = $file['name'];
|
||||
}
|
||||
|
||||
public function rename($name, $extension = null) {
|
||||
$info = pathinfo($this->name);
|
||||
$this->name = $name . '.' . ( isset($extension) ? $extension : $info['extension'] );
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getFilename() {
|
||||
return $this->file['tmp_name'];
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return basename($this->name);
|
||||
}
|
||||
|
||||
public function getNameWithoutExtension() {
|
||||
$info = pathinfo($this->name);
|
||||
return $info['filename'];
|
||||
}
|
||||
|
||||
public function getExtension() {
|
||||
$info = pathinfo($this->name);
|
||||
return $info['extension'];
|
||||
}
|
||||
|
||||
public function getSize() {
|
||||
return $this->file['size'];
|
||||
}
|
||||
|
||||
public function getType() {
|
||||
return $this->file['mime'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
<?php
|
||||
|
||||
namespace Bolt\Media;
|
||||
|
||||
use Bolt\Configuration\Config;
|
||||
|
||||
/**
|
||||
* FilePond RequestHandler helper class
|
||||
*/
|
||||
|
||||
/*
|
||||
1. get files (from $files and $post)
|
||||
2. store files in tmp/ directory and give them a unique server id
|
||||
3. return server id's to client
|
||||
4. either client reverts upload or finalizes form
|
||||
5. call revert($server_id) to remove file from tmp/ directory
|
||||
6. call save() to save file to final directory
|
||||
*/
|
||||
class RequestHandler
|
||||
{
|
||||
// the default location to save tmp files to
|
||||
private $tmp_dir;
|
||||
|
||||
// regex to use for testing if a string is a file id
|
||||
private $file_id_format = '/^[0-9a-fA-F]{32}$/';
|
||||
|
||||
/** @var Config */
|
||||
private $config;
|
||||
|
||||
public function __construct(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
$this->tmp_dir = $this->config->getPath('cache', true, ['uploads']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @return bool
|
||||
*/
|
||||
public function isFileId($str) {
|
||||
return preg_match($this->file_id_format, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @return bool
|
||||
*/
|
||||
public function isURL($str) {
|
||||
return filter_var($str, FILTER_VALIDATE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch all exceptions so we can return a 500 error when the server bugs out
|
||||
*/
|
||||
public function catchExceptions() {
|
||||
set_exception_handler('FilePond\RequestHandler::handleException');
|
||||
}
|
||||
|
||||
public function handleException($ex) {
|
||||
|
||||
// write to error log so we can still find out what's up
|
||||
error_log('Uncaught exception in class="' . get_class($ex) . '" message="' . $ex->getMessage() . '" line="' . $ex->getLine() . '"');
|
||||
|
||||
// clean up buffer
|
||||
ob_end_clean();
|
||||
|
||||
// server error mode go!
|
||||
http_response_code(500);
|
||||
}
|
||||
|
||||
private function createItem($file, $id = null) {
|
||||
return new Item($file, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $fieldName
|
||||
* @return array
|
||||
*/
|
||||
public function loadFilesByField($fieldName) {
|
||||
|
||||
// See if files are posted as JSON string (each file being base64 encoded)
|
||||
$base64Items = $this->loadBase64FormattedFiles($fieldName);
|
||||
|
||||
// retrieves posted file objects
|
||||
$fileItems = $this->loadFileObjects($fieldName);
|
||||
|
||||
// retrieves files already on server
|
||||
$tmpItems = $this->loadFilesFromTemp($fieldName);
|
||||
|
||||
// save newly received files to temp files folder (tmp items already are in that folder)
|
||||
$this->saveAsTempFiles(array_merge($base64Items, $fileItems));
|
||||
|
||||
// return items
|
||||
return array_merge($base64Items, $fileItems, $tmpItems);
|
||||
}
|
||||
|
||||
private function loadFileObjects($fieldName) {
|
||||
|
||||
$items = [];
|
||||
|
||||
if ( !isset($_FILES[$fieldName]) ) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
$FILE = $_FILES[$fieldName];
|
||||
|
||||
if (is_array($FILE['tmp_name'])) {
|
||||
|
||||
foreach( $FILE['tmp_name'] as $index => $tmpName ) {
|
||||
|
||||
array_push( $items, $this->createItem( array(
|
||||
'tmp_name' => $FILE['tmp_name'][$index],
|
||||
'name' => $FILE['name'][$index],
|
||||
'size' => $FILE['size'][$index],
|
||||
'error' => $FILE['error'][$index],
|
||||
'type' => $FILE['type'][$index]
|
||||
)) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
array_push( $items, $this->createItem($FILE) );
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function loadBase64FormattedFiles($fieldName) {
|
||||
|
||||
/*
|
||||
// format:
|
||||
{
|
||||
"id": "iuhv2cpsu",
|
||||
"name": "picture.jpg",
|
||||
"type": "image/jpeg",
|
||||
"size": 20636,
|
||||
"metadata" : {...}
|
||||
"data": "/9j/4AAQSkZJRgABAQEASABIAA..."
|
||||
}
|
||||
*/
|
||||
|
||||
$items = [];
|
||||
|
||||
if ( !isset($_POST[$fieldName] ) ) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
// Handle posted files array
|
||||
$values = $_POST[$fieldName];
|
||||
|
||||
// Turn values in array if is submitted as single value
|
||||
if (!is_array($values)) {
|
||||
$values = isset($values) ? array($values) : array();
|
||||
}
|
||||
|
||||
// If files are found, turn base64 strings into actual file objects
|
||||
foreach ($values as $value) {
|
||||
|
||||
// suppress error messages, we'll just investigate the object later
|
||||
$obj = @json_decode($value);
|
||||
|
||||
// skip values that failed to be decoded
|
||||
if (!isset($obj)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// test if this is a file object (matches the object described above)
|
||||
if (!$this->isEncodedFile($obj)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array_push($items, $this->createItem( $this->createTempFile($obj) ) );
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function isEncodedFile($obj) {
|
||||
return isset($obj->id) && isset($obj->data) && isset($obj->name) && isset($obj->type) && isset($obj->size);
|
||||
}
|
||||
|
||||
private function loadFilesFromTemp($fieldName) {
|
||||
|
||||
$items = [];
|
||||
|
||||
if ( !isset($_POST[$fieldName] ) ) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
// Handle posted ids array
|
||||
$values = $_POST[$fieldName];
|
||||
|
||||
// Turn values in array if is submitted as single value
|
||||
if (!is_array($values)) {
|
||||
$values = isset($values) ? array($values) : array();
|
||||
}
|
||||
|
||||
// test if value is actually a file id
|
||||
foreach ($values as $value) {
|
||||
if ( $this->isFileId($value) ) {
|
||||
array_push($items, $this->createItem($this->getTempFile($value), $value));
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
|
||||
}
|
||||
|
||||
public function save($items, $path = 'uploads' . DIRECTORY_SEPARATOR) {
|
||||
|
||||
// is list of files
|
||||
if ( is_array($items) ) {
|
||||
$results = [];
|
||||
foreach($items as $item) {
|
||||
array_push($results, $this->saveFile($item, $path));
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
// is single item
|
||||
return $this->saveFile($items, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file_id
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteTempFile($file_id) {
|
||||
return $this->deleteTempDirectory($file_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @return array|bool
|
||||
*/
|
||||
public function getRemoteURLData($url)
|
||||
{
|
||||
try {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
||||
$content = curl_exec($ch);
|
||||
if ($content === FALSE) {
|
||||
throw new Exception(curl_error($ch), curl_errno($ch));
|
||||
}
|
||||
|
||||
$type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
$length = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close ($ch);
|
||||
|
||||
$success = $code >= 200 && $code < 300;
|
||||
|
||||
return array(
|
||||
'code' => $code,
|
||||
'content' => $content,
|
||||
'type' => $type,
|
||||
'length' => $length,
|
||||
'success' => $success
|
||||
);
|
||||
|
||||
}
|
||||
catch(Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function saveAsTempFiles($items) {
|
||||
foreach($items as $item) {
|
||||
$this->saveTempFile($item);
|
||||
}
|
||||
}
|
||||
|
||||
private function saveTempFile($file) {
|
||||
|
||||
// make sure path name is safe
|
||||
$path = $this->getSecureTempPath() . $file->getId() . DIRECTORY_SEPARATOR;
|
||||
|
||||
// Creates a secure temporary directory to store the files in
|
||||
$this->createSecureDirectory($path);
|
||||
|
||||
// get source and target values
|
||||
$source = $file->getFilename();
|
||||
$target = $path . $file->getName();
|
||||
|
||||
// Move uploaded file to this new secure directory
|
||||
$result = $this->moveFile($source, $target);
|
||||
|
||||
// Was not saved
|
||||
if ($result !== true) { return $result; }
|
||||
|
||||
// Make sure file is secure
|
||||
$this->setSecureFilePermissions($target);
|
||||
|
||||
// temp file stored successfully
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTempFile($fileId) {
|
||||
|
||||
// select all files in directory except .htaccess
|
||||
foreach(glob($this->getSecureTempPath() . $fileId . DIRECTORY_SEPARATOR . '*.*') as $file) {
|
||||
|
||||
try {
|
||||
|
||||
$handle = fopen($file, 'r');
|
||||
$content = fread($handle, filesize($file));
|
||||
fclose($handle);
|
||||
|
||||
return array(
|
||||
'name' => basename($file),
|
||||
'content' => $content,
|
||||
'type' => mime_content_type($file),
|
||||
'length' => filesize($file)
|
||||
);
|
||||
|
||||
}
|
||||
catch(Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFile($file, $path) {
|
||||
|
||||
try {
|
||||
|
||||
$filename = $path . DIRECTORY_SEPARATOR . $file;
|
||||
$handle = fopen($filename, 'r');
|
||||
$content = fread($handle, filesize($filename));
|
||||
fclose($handle);
|
||||
|
||||
return array(
|
||||
'name' => basename($filename),
|
||||
'content' => $content,
|
||||
'type' => mime_content_type($filename),
|
||||
'length' => filesize($filename)
|
||||
);
|
||||
|
||||
}
|
||||
catch(Exception $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function saveFile($item, $path) {
|
||||
|
||||
// nope
|
||||
if (!isset($item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if is file id
|
||||
if (is_string($item)) {
|
||||
return $this->moveFileById($item, $path);
|
||||
}
|
||||
|
||||
// is file object
|
||||
else {
|
||||
return $this->moveFileById($item->getId(), $path, $item->getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function moveFileById($fileId, $path, $fileName = null) {
|
||||
|
||||
// select all files in directory except .htaccess
|
||||
foreach(glob($this->getSecureTempPath() . $fileId . DIRECTORY_SEPARATOR . '*.*') as $file) {
|
||||
|
||||
$source = $file;
|
||||
$target = $this->getSecurePath($path);
|
||||
|
||||
$this->createDirectory($target);
|
||||
|
||||
rename($source, $target . (isset($fileName) ? basename($fileName) : basename($file)));
|
||||
}
|
||||
|
||||
// remove directory
|
||||
$this->deleteTempDirectory($fileId);
|
||||
|
||||
// done!
|
||||
return true;
|
||||
}
|
||||
|
||||
private function deleteTempDirectory($id) {
|
||||
|
||||
@array_map('unlink', glob($this->getSecureTempPath() . $id . DIRECTORY_SEPARATOR . '{.,}*', GLOB_BRACE));
|
||||
|
||||
// remove temp directory
|
||||
@rmdir($this->getSecureTempPath() . $id);
|
||||
|
||||
}
|
||||
|
||||
private function createTempFile($file) {
|
||||
|
||||
$tmp = tmpfile();
|
||||
fwrite($tmp, base64_decode($file->data));
|
||||
$meta = stream_get_meta_data($tmp);
|
||||
$filename = $meta['uri'];
|
||||
|
||||
return array(
|
||||
'error' => 0,
|
||||
'size' => filesize($filename),
|
||||
'type' => $file->type,
|
||||
'name' => $file->name,
|
||||
'tmp_name' => $filename,
|
||||
'tmp' => $tmp
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private function moveFile($source, $target) {
|
||||
|
||||
if (is_uploaded_file($source)) {
|
||||
return move_uploaded_file($source, $target);
|
||||
}
|
||||
else {
|
||||
$tmp = fopen($source, 'r');
|
||||
$result = file_put_contents( $target, fread($tmp, filesize($source) ) );
|
||||
fclose($tmp);
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getSecurePath($path) {
|
||||
return pathinfo($path)['dirname'] . DIRECTORY_SEPARATOR . basename($path) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
private function getSecureTempPath() {
|
||||
return $this->getSecurePath($this->tmp_dir);
|
||||
}
|
||||
|
||||
private function setSecureFilePermissions($target) {
|
||||
$stat = stat( dirname($target) );
|
||||
$perms = $stat['mode'] & 0000666;
|
||||
@chmod($target, $perms);
|
||||
}
|
||||
|
||||
private function createDirectory($path) {
|
||||
if (is_dir($path)) {
|
||||
return false;
|
||||
}
|
||||
mkdir($path, 0755, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function createSecureDirectory($path) {
|
||||
|
||||
// !! If directory already exists we assume security is handled !!
|
||||
|
||||
// Test if directory already exists and correct
|
||||
if ($this->createDirectory($path)) {
|
||||
|
||||
// Add .htaccess file for security purposes
|
||||
$content = '# Don\'t list directory contents
|
||||
IndexIgnore *
|
||||
# Disable script execution
|
||||
AddHandler cgi-script .php .pl .jsp .asp .sh .cgi
|
||||
Options -ExecCGI -Indexes';
|
||||
file_put_contents($path . '.htaccess', $content);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{% set dimensions = '' %}
|
||||
|
||||
{% if extension in imageformats %}
|
||||
{% set thumbnail = filename|thumbnail(100, 72) %}
|
||||
{% set thumbnail = filename|thumbnail(width = 100, height = 72, area = area) %}
|
||||
{% set icon = 'fa-image' %}
|
||||
{% set link = path('bolt_media_new', {'area': area, 'file': filename}) %}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<link rel="stylesheet" href="https://unpkg.com/filepond/dist/filepond.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css">
|
||||
|
||||
<script src="https://unpkg.com/filepond-plugin-image-preview"></script>
|
||||
<script src="https://unpkg.com/filepond-plugin-file-metadata/dist/filepond-plugin-file-metadata.js"></script>
|
||||
<script src="https://unpkg.com/filepond"></script>
|
||||
<script src="https://unpkg.com/vue"></script>
|
||||
<script src="https://unpkg.com/vue-filepond"></script>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">File uploader</div>
|
||||
<div id="uploader">
|
||||
<file-pond name="filepond[]"
|
||||
ref="pond"
|
||||
allow-multiple="true"
|
||||
accepted-file-types="image/jpeg, image/png"
|
||||
server="/async/upload"></file-pond>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
FilePond.registerPlugin(
|
||||
FilePondPluginFileMetadata,
|
||||
FilePondPluginImagePreview
|
||||
);
|
||||
FilePond.setOptions({
|
||||
fileMetadataObject: {
|
||||
'area': '{{ area }}',
|
||||
'path': '{{ path }}'
|
||||
}
|
||||
});
|
||||
|
||||
new Vue({
|
||||
el: '#uploader',
|
||||
components: {
|
||||
FilePond: vueFilePond.default()
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -18,13 +18,16 @@
|
||||
|
||||
{% block aside %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Meta information</div>
|
||||
<div class="card-body">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include '@bolt/finder/_uploader.twig' %}
|
||||
|
||||
|
||||
|
||||
{% endblock aside %}
|
||||
|
||||
@@ -32,6 +35,11 @@
|
||||
{{ parent() }}
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.6/css/selectize.min.css" integrity="sha256-EhmqrzYSImS7269rfDxk4H+AHDyu/KwV1d8FDgIXScI=" crossorigin="anonymous" />
|
||||
<style>
|
||||
.filepond--root {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user