diff --git a/Classes/Domain/Model/FileReference.php b/Classes/Domain/Model/FileReference.php new file mode 100644 index 0000000..b1c3a2c --- /dev/null +++ b/Classes/Domain/Model/FileReference.php @@ -0,0 +1,50 @@ +originalResource = $originalResource; + $this->originalFileIdentifier = (int)$originalResource->getOriginalFile()->getUid(); + } +} diff --git a/Classes/Domain/Model/Upload.php b/Classes/Domain/Model/Upload.php new file mode 100644 index 0000000..d5cb4e7 --- /dev/null +++ b/Classes/Domain/Model/Upload.php @@ -0,0 +1,125 @@ + + */ + protected $imageCollection; + + public function __construct() + { + $this->imageCollection = new ObjectStorage(); + } + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() + { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() + { + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage($image) + { + $this->image = $image; + } + + /** + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage + */ + public function getImageCollection() + { + return $this->imageCollection; + } + + /** + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $imageCollection + */ + public function setImageCollection($imageCollection) + { + $this->imageCollection = $imageCollection; + } + +} diff --git a/Classes/Domain/Repository/UploadRepository.php b/Classes/Domain/Repository/UploadRepository.php new file mode 100644 index 0000000..8da6ff4 --- /dev/null +++ b/Classes/Domain/Repository/UploadRepository.php @@ -0,0 +1,38 @@ + $propertyValue) { + if ($this->isUploadType($propertyValue)) { + if ($propertyValue['error'] !== \UPLOAD_ERR_NO_FILE || isset($propertyValue['submittedFile']['resourcePointer'])) { + $propertiesToConvert[$propertyName] = $propertyValue; + } + } else { + $propertiesToConvert[$propertyName] = $propertyValue; + } + } + + return $propertiesToConvert; + } + + /** + * Check if this is an upload type + * + * @param mixed $propertyValue + * @return bool + */ + protected function isUploadType($propertyValue) + { + return is_array($propertyValue) && isset($propertyValue['tmp_name']) && isset($propertyValue['error']); + } + +} \ No newline at end of file diff --git a/Classes/Property/TypeConverter/UploadedFileReferenceConverter.php b/Classes/Property/TypeConverter/UploadedFileReferenceConverter.php new file mode 100644 index 0000000..77c5b56 --- /dev/null +++ b/Classes/Property/TypeConverter/UploadedFileReferenceConverter.php @@ -0,0 +1,316 @@ + + */ + protected $sourceTypes = array('array'); + + /** + * @var string + */ + protected $targetType = 'TYPO3\\CMS\\Extbase\\Domain\\Model\\FileReference'; + + /** + * Take precedence over the available FileReferenceConverter + * + * @var integer + */ + protected $priority = 2; + + /** + * @var \TYPO3\CMS\Core\Resource\ResourceFactory + * + */ + protected $resourceFactory; + + /** + * @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService + * + */ + protected $hashService; + + /** + * @var \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager + * + */ + protected $persistenceManager; + + /** + * @var \TYPO3\CMS\Core\Resource\FileInterface[] + */ + protected $convertedResources = array(); + + /** + * Actually convert from $source to $targetType, taking into account the fully + * built $convertedChildProperties and $configuration. + * + * @param string|integer $source + * @param string $targetType + * @param array $convertedChildProperties + * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration + * @return \TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder|Error + * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException + * @throws \TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException + * @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException + * @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidHashException + * @api + */ + public function convertFrom( + $source, + $targetType, + array $convertedChildProperties = array(), + PropertyMappingConfigurationInterface $configuration = null + ) { + if (!isset($source['error']) || $source['error'] === \UPLOAD_ERR_NO_FILE) { + if (isset($source['submittedFile']['resourcePointer'])) { + try { + $resourcePointer = $this->hashService->validateAndStripHmac($source['submittedFile']['resourcePointer']); + if (strpos($resourcePointer, 'file:') === 0) { + $fileUid = substr($resourcePointer, 5); + return $this->createFileReferenceFromFalFileObject($this->resourceFactory->getFileObject($fileUid)); + } else { + return $this->createFileReferenceFromFalFileReferenceObject($this->resourceFactory->getFileReferenceObject($resourcePointer), + $resourcePointer); + } + } catch (\InvalidArgumentException $e) { + // Nothing to do. No file is uploaded and resource pointer is invalid. Discard! + } + } + return null; + } + + if ($source['error'] !== \UPLOAD_ERR_OK) { + switch ($source['error']) { + case \UPLOAD_ERR_INI_SIZE: + case \UPLOAD_ERR_FORM_SIZE: + case \UPLOAD_ERR_PARTIAL: + return new Error($this->getUploadErrorMessage($source['error']), 1264440823); + default: + return new Error('An error occurred while uploading. Please try again or contact the administrator if the problem remains', + 1340193849); + } + } + + if (isset($this->convertedResources[$source['tmp_name']])) { + return $this->convertedResources[$source['tmp_name']]; + } + + try { + $resource = $this->importUploadedResource($source, $configuration); + } catch (\Exception $e) { + return new Error($e->getMessage(), $e->getCode()); + } + + $this->convertedResources[$source['tmp_name']] = $resource; + return $resource; + } + + /** + * @param FalFile $file + * @param int $resourcePointer + * @return \Mindscreen\FalUpload\Domain\Model\FileReference + */ + protected function createFileReferenceFromFalFileObject(FalFile $file, $resourcePointer = null) + { + $fileReference = $this->resourceFactory->createFileReferenceObject( + array( + 'uid_local' => $file->getUid(), + 'uid_foreign' => uniqid('NEW_'), + 'uid' => uniqid('NEW_'), + 'crop' => null, + ) + ); + return $this->createFileReferenceFromFalFileReferenceObject($fileReference, $resourcePointer); + } + + /** + * @param FalFileReference $falFileReference + * @param int $resourcePointer + * @return \Mindscreen\FalUpload\Domain\Model\FileReference + */ + protected function createFileReferenceFromFalFileReferenceObject( + FalFileReference $falFileReference, + $resourcePointer = null + ) { + if ($resourcePointer === null) { + /** @var $fileReference \Mindscreen\FalUpload\Domain\Model\FileReference */ + $fileReference = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Domain\\Model\\FileReference'); + + } else { + $fileReference = $this->persistenceManager->getObjectByIdentifier($resourcePointer, + 'TYPO3\\CMS\\Extbase\\Domain\\Model\\FileReference', false); + } + + $fileReference->setOriginalResource($falFileReference); + + return $fileReference; + } + + /** + * Returns a human-readable message for the given PHP file upload error + * constant. + * + * @param int $errorCode + * @return string + */ + protected function getUploadErrorMessage(int $errorCode): string + { + switch ($errorCode) { + case \UPLOAD_ERR_INI_SIZE: + return 'The uploaded file exceeds the upload_max_filesize directive in php.ini'; + case \UPLOAD_ERR_FORM_SIZE: + return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'; + case \UPLOAD_ERR_PARTIAL: + return 'The uploaded file was only partially uploaded'; + case \UPLOAD_ERR_NO_FILE: + return 'No file was uploaded'; + case \UPLOAD_ERR_NO_TMP_DIR: + return 'Missing a temporary folder'; + case \UPLOAD_ERR_CANT_WRITE: + return 'Failed to write file to disk'; + case \UPLOAD_ERR_EXTENSION: + return 'File upload stopped by extension'; + default: + return 'Unknown upload error'; + } + } + + /** + * Import a resource and respect configuration given for properties + * + * @param array $uploadInfo + * @param PropertyMappingConfigurationInterface $configuration + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @throws TypeConverterException + * @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidArgumentForHashGenerationException + * @throws \TYPO3\CMS\Extbase\Security\Exception\InvalidHashException + */ + protected function importUploadedResource(array $uploadInfo, PropertyMappingConfigurationInterface $configuration) + { + if (!GeneralUtility::verifyFilenameAgainstDenyPattern($uploadInfo['name'])) { + throw new TypeConverterException('Uploading files with PHP file extensions is not allowed!', 1399312430); + } + + $allowedFileExtensions = $configuration->getConfigurationValue( + UploadedFileReferenceConverter::class, + self::CONFIGURATION_ALLOWED_FILE_EXTENSIONS + ); + + if ($allowedFileExtensions !== null) { + $filePathInfo = PathUtility::pathinfo($uploadInfo['name']); + if (!GeneralUtility::inList($allowedFileExtensions, strtolower($filePathInfo['extension']))) { + throw new TypeConverterException('File extension is not allowed!', 1399312430); + } + } + + $uploadFolderId = $configuration->getConfigurationValue( + UploadedFileReferenceConverter::class, + self::CONFIGURATION_UPLOAD_FOLDER + ) ?: $this->defaultUploadFolder; + $conflictMode = $configuration->getConfigurationValue( + UploadedFileReferenceConverter::class, + self::CONFIGURATION_UPLOAD_CONFLICT_MODE + ) ?: $this->defaultConflictMode; + + $uploadFolder = $this->resourceFactory->retrieveFileOrFolderObject($uploadFolderId); + $uploadedFile = $uploadFolder->addUploadedFile($uploadInfo, $conflictMode); + + $resourcePointer = null; + if ( + isset($uploadInfo['submittedFile']['resourcePointer']) && + strpos($uploadInfo['submittedFile']['resourcePointer'], 'file:') === false + ) { + $resourcePointer = $this->hashService->validateAndStripHmac($uploadInfo['submittedFile']['resourcePointer']); + } + + $fileReferenceModel = $this->createFileReferenceFromFalFileObject($uploadedFile, $resourcePointer); + + return $fileReferenceModel; + } + + public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService) + { + $this->hashService = $hashService; + } + + public function injectPersistenceManager( + \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager $persistenceManager + ) { + $this->persistenceManager = $persistenceManager; + } + + public function injectResourceFactory(\TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory) + { + $this->resourceFactory = $resourceFactory; + } +} \ No newline at end of file diff --git a/Classes/ViewHelpers/Form/UploadViewHelper.php b/Classes/ViewHelpers/Form/UploadViewHelper.php new file mode 100644 index 0000000..1515e81 --- /dev/null +++ b/Classes/ViewHelpers/Form/UploadViewHelper.php @@ -0,0 +1,116 @@ +getUploadedResource(); + if ($resource !== null) { + $resourcePointerIdAttribute = ''; + if ($this->hasArgument('id')) { + $resourcePointerIdAttribute = ' id="' . htmlspecialchars($this->arguments['id']) . '-file-reference"'; + } + $resourcePointerValue = $resource->getUid(); + if ($resourcePointerValue === null) { + // Newly created file reference which is not persisted yet. + // Use the file UID instead, but prefix it with "file:" to communicate this to the type converter + $resourcePointerValue = 'file:' . $resource->getOriginalResource()->getOriginalFile()->getUid(); + } + $output .= ''; + + $this->templateVariableContainer->add('resource', $resource); + $output .= $this->renderChildren(); + $this->templateVariableContainer->remove('resource'); + } + + $output .= parent::render(); + return $output; + } + + + /** + * Return a previously uploaded resource. + * Return NULL if errors occurred during property mapping for this property. + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @throws \TYPO3\CMS\Extbase\Property\Exception + */ + protected function getUploadedResource() + { + if ($this->getMappingResultsForProperty()->hasErrors()) { + return null; + } + $resource = $this->getValueFromSubmittedFormData(null); + if ($resource instanceof \TYPO3\CMS\Extbase\Domain\Model\FileReference) { + return $resource; + } + return $this->propertyMapper->convert($resource, 'TYPO3\\CMS\\Extbase\\Domain\\Model\\FileReference'); + } + + public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService) + { + $this->hashService = $hashService; + } + + public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper) + { + $this->propertyMapper = $propertyMapper; + } + + +} \ No newline at end of file diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php new file mode 100644 index 0000000..c39e6bc --- /dev/null +++ b/Configuration/TCA/Overrides/sys_template.php @@ -0,0 +1,6 @@ + array( + 'title' => 'LLL:EXT:fal_upload/Resources/Private/Language/locallang_db.xlf:tx_falupload_domain_model_upload', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'dividers2tabs' => true, + + 'versioningWS' => 2, + 'versioning_followPages' => true, + + 'origUid' => 't3_origuid', + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + + 'delete' => 'deleted', + 'enablecolumns' => array( + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ), + 'searchFields' => 'title,', + 'iconfile' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($_EXTKEY) . 'ext_icon.svg' + ), + 'interface' => array( + 'showRecordFieldList' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, image', + ), + 'types' => array( + '1' => array('showitem' => 'sys_language_uid;;;;1-1-1, l10n_parent, l10n_diffsource, hidden;;1, title, image,image_collection,--div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access,starttime, endtime'), + ), + 'palettes' => array( + '1' => array('showitem' => ''), + ), + 'columns' => array( + + 'sys_language_uid' => array( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.language', + 'config' => array( + 'type' => 'select', + 'foreign_table' => 'sys_language', + 'foreign_table_where' => 'ORDER BY sys_language.title', + 'items' => array( + array('LLL:EXT:lang/locallang_general.xlf:LGL.allLanguages', -1), + array('LLL:EXT:lang/locallang_general.xlf:LGL.default_value', 0) + ), + ), + ), + 'l10n_parent' => array( + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.l18n_parent', + 'config' => array( + 'type' => 'select', + 'items' => array( + array('', 0), + ), + 'foreign_table' => 'tx_falupload_domain_model_upload', + 'foreign_table_where' => 'AND tx_falupload_domain_model_upload.pid=###CURRENT_PID### AND tx_falupload_domain_model_upload.sys_language_uid IN (-1,0)', + ), + ), + 'l10n_diffsource' => array( + 'config' => array( + 'type' => 'passthrough', + ), + ), + + 't3ver_label' => array( + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.versionLabel', + 'config' => array( + 'type' => 'input', + 'size' => 30, + 'max' => 255, + ) + ), + + 'hidden' => array( + 'exclude' => 1, + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.hidden', + 'config' => array( + 'type' => 'check', + ), + ), + 'starttime' => array( + 'exclude' => 1, + 'l10n_mode' => 'mergeIfNotBlank', + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.starttime', + 'config' => array( + 'type' => 'input', + 'size' => 13, + 'max' => 20, + 'eval' => 'datetime', + 'checkbox' => 0, + 'default' => 0, + ), + ), + 'endtime' => array( + 'exclude' => 1, + 'l10n_mode' => 'mergeIfNotBlank', + 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.endtime', + 'config' => array( + 'type' => 'input', + 'size' => 13, + 'max' => 20, + 'eval' => 'datetime', + 'checkbox' => 0, + 'default' => 0, + ), + ), + 'title' => array( + 'exclude' => 0, + 'label' => 'LLL:EXT:fal_upload/Resources/Private/Language/locallang_db.xlf:tx_falupload_domain_model_upload.title', + 'config' => array( + 'type' => 'input', + 'max' => 20, + 'size' => 30, + 'eval' => 'trim,required' + ), + ), + 'image' => array( + 'exclude' => 0, + 'label' => 'LLL:EXT:fal_upload/Resources/Private/Language/locallang_db.xlf:tx_falupload_domain_model_upload.image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('image', array( + 'appearance' => array( + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ), + 'maxitems' => 1, + // custom configuration for displaying fields in the overlay/reference table + // to use the imageoverlayPalette instead of the basicoverlayPalette + 'foreign_match_fields' => array( + 'fieldname' => 'image', + 'tablenames' => 'tx_falupload_domain_model_upload', + 'table_local' => 'sys_file', + ), + 'foreign_types' => array( + '0' => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ) + ) + ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']) + ), + 'image_collection' => array( + 'exclude' => 0, + 'label' => 'LLL:EXT:fal_upload/Resources/Private/Language/locallang_db.xlf:tx_falupload_domain_model_upload.image_collection', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig('image_collection', + array( + 'appearance' => array( + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ), + // custom configuration for displaying fields in the overlay/reference table + // to use the imageoverlayPalette instead of the basicoverlayPalette + 'foreign_match_fields' => array( + 'fieldname' => 'image_collection', + 'tablenames' => 'tx_falupload_domain_model_upload', + 'table_local' => 'sys_file', + ), + 'foreign_types' => array( + '0' => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ), + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => array( + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ) + ) + ), $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']) + ), + ), +); diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..c9d6088 --- /dev/null +++ b/README.rst @@ -0,0 +1,194 @@ + +================================================ +File Upload using Extbase and FAL in TYPO3 > 6.2 +================================================ + +.. post:: + :tags: TYPO3, Extbase + + + + +.. highlight:: php +.. default-role:: code + + +:Project: + TYPO3 CMS extension ext:fal_upload for TYPO3 >= 6.2.4 + +:Author: + `Michael Telgkamp `__ + +:Repository: + At Github `mindscreen/t3ext-fal_upload `__ + +:Credit: + - `Helmut Hummel `__ - for his extension `fal_upload `__ as inspiration + + +**Overview:** + +.. contents:: + :local: + :depth: 3 + :backlinks: none + + + +What does it do? +================ + +This is an extension simplifying the addition of file upload functionality in other extensions. + + +How does it work? +================= + +- The heart of the extension is the UploadedFileReferenceConverter +- an extended FileReference model is needed +- an extended ObjectStorageConverter is needed +- an extended UploadViewHelper is needed + + +What needs to be done? +====================== + +TypeConverter +------------- + +We want to have a custom TypeConverter to: + +- evaluate the file upload array +- move the uploaded file to a FAL storage using the FAL API +- and have the result persisted in the database using the Extbase persistence. + + +Error handling +-------------- + +We don't want to just throw exceptions but use the TypeConverter API +to return useful error messages to the user. + + +Configurability +--------------- + +Things should be configurable, especially the TypeConverter. It needs to know +about + +1. the folder to upload to +2. what to do in case of a name conflict for the uploaded file +3. the allowed file extensions +4. how to deal with an already attached resource. + +The actual configuration is done through by PropertyMappingConfiguration. + +Some configuration options:: + + + + + +
+ + +Case: Upload succeeds, validation fails +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this case the file upload succeeds but due to validation errors in some other +fields the whole form isn't accepted. This also means it isn't persisted yet but we +nevertheless want to keep the uploaded file as a resource as we don't want to upload it again. + +Security +-------- + +To make file upload secure the TypeConverter needs at least needs to care about these two issues: + +1. Deny upload of PHP files! :: + + `__ +- `Use the issue tracker for feedback and discussions. `__ + +Enjoy! diff --git a/Resources/Private/.htaccess b/Resources/Private/.htaccess new file mode 100644 index 0000000..2e8cdb8 --- /dev/null +++ b/Resources/Private/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf new file mode 100644 index 0000000..2aecf45 --- /dev/null +++ b/Resources/Private/Language/locallang_db.xlf @@ -0,0 +1,23 @@ + + + +
+ + + + FAL Upload + + + Title + + + Image + + + + Image Collection + + + + \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4256328 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "mindscreen/fal_upload", + "type": "typo3-cms-extension", + "description": "Handling file uploads via Extbase inspired by fal_upload of helhum", + "homepage": "https://github.com/mindscreen/t3ext-fal_upload", + "license": [ + "GPL-2.0+" + ], + "version": "0.1.0", + "require": { + "typo3/cms-core": ">=6.2.4,<9.0" + }, + "autoload": { + "psr-4": { + "Mindscreen\\FalUpload\\": "Classes" + } + } +} diff --git a/ext_emconf.php b/ext_emconf.php new file mode 100644 index 0000000..8a84ce8 --- /dev/null +++ b/ext_emconf.php @@ -0,0 +1,18 @@ + 'FAL Upload', + 'description' => 'Handling file uploads via Extbase inspired by fal_upload of helhum', + 'category' => 'fe', + 'author' => 'Michael Telgkamp', + 'author_email' => 'michael.telgkamp@mindscreen.de', + 'author_company' => 'mindscreen GmbH', + 'state' => 'beta', + 'version' => '0.1.0', + 'constraints' => array( + 'depends' => array( + 'typo3' => '6.2.4-8.99.99', + ), + 'conflicts' => array(), + 'suggests' => array(), + ), +); \ No newline at end of file diff --git a/ext_icon.gif b/ext_icon.gif new file mode 100644 index 0000000..3d28eab Binary files /dev/null and b/ext_icon.gif differ diff --git a/ext_icon.svg b/ext_icon.svg new file mode 100644 index 0000000..dabbd37 --- /dev/null +++ b/ext_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ext_localconf.php b/ext_localconf.php new file mode 100644 index 0000000..64d83d3 --- /dev/null +++ b/ext_localconf.php @@ -0,0 +1,6 @@ +