/** * Check extension of given filename * * @param string $filename Filename like (upload.png) * @return bool If Extension is allowed */ public static function checkExtension($filename) { $extensionList = 'jpg,jpeg,png,gif,bmp'; $settings = self::getTypoScriptFrontendController()->tmpl->setup['plugin.']['tx_femanager.']['settings.']; if (!empty($settings['misc.']['uploadFileExtension'])) { $extensionList = $settings['misc.']['uploadFileExtension']; $extensionList = str_replace(' ', '', $extensionList); } $fileInfo = pathinfo($filename); return !empty($fileInfo['extension']) && GeneralUtility::inList($extensionList, strtolower($fileInfo['extension'])) && GeneralUtility::verifyFilenameAgainstDenyPattern($filename) && GeneralUtility::validPathStr($filename); }
/** * @param array $information * @param string $expectedFileType * @return bool * @throws \Exception */ public static function isUploadedFileGood(array $information, $expectedFileType = 'text/csv') { if (isset($information['error'])) { if ($information['error'] === UPLOAD_ERR_OK) { if (!GeneralUtility::verifyFilenameAgainstDenyPattern($information['name'])) { throw new \Exception('Uploading files with PHP file extensions is not allowed!', 1399312430); } return $information['type'] === $expectedFileType; } } return false; }
/** * Tests whether verifyFilenameAgainstDenyPattern detects denied files. * * @param string $deniedFile * @test * @dataProvider deniedFilesDataProvider */ public function verifyFilenameAgainstDenyPatternDetectsNotAllowedFiles($deniedFile) { $this->assertFalse(GeneralUtility::verifyFilenameAgainstDenyPattern($deniedFile)); }
/** * 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 ExistingTargetFileNameException */ 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('Bureauoberhoff\\H5upldr\\Property\\TypeConverter\\UploadedFileReferenceConverter', 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('Bureauoberhoff\\H5upldr\\Property\\TypeConverter\\UploadedFileReferenceConverter', self::CONFIGURATION_UPLOAD_FOLDER) ?: $this->defaultUploadFolder; $conflictMode = $configuration->getConfigurationValue('Bureauoberhoff\\H5upldr\\Property\\TypeConverter\\UploadedFileReferenceConverter', self::CONFIGURATION_UPLOAD_CONFLICT_MODE) ?: $this->defaultConflictMode; $uploadFolder = $this->resourceFactory->retrieveFileOrFolderObject($uploadFolderId); $uploadedFile = $uploadFolder->addUploadedFile($uploadInfo, $conflictMode); $resourcePointer = isset($uploadInfo['submittedFile']['resourcePointer']) && strpos($uploadInfo['submittedFile']['resourcePointer'], 'file:') === FALSE ? $this->hashService->validateAndStripHmac($uploadInfo['submittedFile']['resourcePointer']) : NULL; $fileReferenceModel = $this->createFileReferenceFromFalFileObject($uploadedFile, $resourcePointer); return $fileReferenceModel; }
/** * Display some warning messages if this installation is obviously insecure!! * These warnings are only displayed to admin users * * @return void */ public static function displayWarningMessages() { if ($GLOBALS['BE_USER']->isAdmin()) { // Array containing warnings that must be displayed $warnings = array(); // If this file exists and it isn't older than one hour, the Install Tool is enabled $enableInstallToolFile = PATH_site . 'typo3conf/ENABLE_INSTALL_TOOL'; // Cleanup command, if set $cmd = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('adminWarning_cmd'); switch ($cmd) { case 'remove_ENABLE_INSTALL_TOOL': if (unlink($enableInstallToolFile)) { unset($enableInstallToolFile); } break; } // Check if the Install Tool Password is still default: joh316 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'] == md5('joh316')) { $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=about'); $warnings['install_password'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_password'), '<a href="' . $url . '">', '</a>'); } // Check if there is still a default user 'admin' with password 'password' (MD5sum = 5f4dcc3b5aa765d61d8327deb882cf99) $where_clause = 'username='******'TYPO3_DB']->fullQuoteStr('admin', 'be_users') . ' AND password='******'TYPO3_DB']->fullQuoteStr('5f4dcc3b5aa765d61d8327deb882cf99', 'be_users') . self::deleteClause('be_users'); $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid, username, password', 'be_users', $where_clause); if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $url = 'alt_doc.php?returnUrl=alt_intro.php&edit[be_users][' . $row['uid'] . ']=edit'; $warnings['backend_admin'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.backend_admin'), '<a href="' . htmlspecialchars($url) . '">', '</a>'); } $GLOBALS['TYPO3_DB']->sql_free_result($res); // Check whether the file ENABLE_INSTALL_TOOL contains the string "KEEP_FILE" which permanently unlocks the install tool if (is_file($enableInstallToolFile) && trim(file_get_contents($enableInstallToolFile)) === 'KEEP_FILE') { $url = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_REQUEST_SCRIPT') . '?adminWarning_cmd=remove_ENABLE_INSTALL_TOOL'; $warnings['install_enabled'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled'), '<span style="white-space:nowrap;">' . $enableInstallToolFile . '</span>'); $warnings['install_enabled'] .= ' <a href="' . $url . '">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_enabled_cmd') . '</a>'; } // Check if the encryption key is empty if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] == '') { $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=config#set_encryptionKey'); $warnings['install_encryption'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_encryption'), '<a href="' . $url . '">', '</a>'); } // Check if parts of fileDenyPattern were removed which is dangerous on Apache $defaultParts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('|', FILE_DENY_PATTERN_DEFAULT, TRUE); $givenParts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('|', $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'], TRUE); $result = array_intersect($defaultParts, $givenParts); if ($defaultParts !== $result) { $warnings['file_deny_pattern'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_pattern_partsNotPresent'), '<br /><pre>' . htmlspecialchars(FILE_DENY_PATTERN_DEFAULT) . '</pre><br />'); } // Check if fileDenyPattern allows to upload .htaccess files which is dangerous on Apache if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT && \TYPO3\CMS\Core\Utility\GeneralUtility::verifyFilenameAgainstDenyPattern('.htaccess')) { $warnings['file_deny_htaccess'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_deny_htaccess'); } // Check if there are still updates to perform if (!\TYPO3\CMS\Core\Utility\GeneralUtility::compat_version(TYPO3_branch)) { $url = 'install/index.php?redirect_url=index.php' . urlencode('?TYPO3_INSTALL[type]=update'); $warnings['install_update'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.install_update'), '<a href="' . $url . '">', '</a>'); } // Check if sys_refindex is empty $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', 'sys_refindex'); $registry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Registry'); $lastRefIndexUpdate = $registry->get('core', 'sys_refindex_lastUpdate'); if (!$count && $lastRefIndexUpdate) { $url = 'sysext/lowlevel/dbint/index.php?&id=0&SET[function]=refindex'; $warnings['backend_reference'] = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.backend_reference_index'), '<a href="' . $url . '">', '</a>', self::dateTime($lastRefIndexUpdate)); } // Check for memcached if configured $memCacheUse = FALSE; if (is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'] as $table => $conf) { if (is_array($conf)) { foreach ($conf as $key => $value) { if (!is_array($value) && $value === 'TYPO3\\CMS\\Core\\Cache\\Backend\\MemcachedBackend') { $servers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations'][$table]['options']['servers']; $memCacheUse = TRUE; break; } } } } if ($memCacheUse) { $failed = array(); $defaultPort = ini_get('memcache.default_port'); if (function_exists('memcache_connect')) { if (is_array($servers)) { foreach ($servers as $testServer) { $configuredServer = $testServer; if (substr($testServer, 0, 7) == 'unix://') { $host = $testServer; $port = 0; } else { if (substr($testServer, 0, 6) === 'tcp://') { $testServer = substr($testServer, 6); } if (strstr($testServer, ':') !== FALSE) { list($host, $port) = explode(':', $testServer, 2); } else { $host = $testServer; $port = $defaultPort; } } $memcache_obj = @memcache_connect($host, $port); if ($memcache_obj != NULL) { memcache_close($memcache_obj); } else { $failed[] = $configuredServer; } } } } if (count($failed) > 0) { $warnings['memcached'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.memcache_not_usable') . '<br/>' . implode(', ', $failed); } } } // Hook for additional warnings if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['displayWarningMessages'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_befunc.php']['displayWarningMessages'] as $classRef) { $hookObj = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classRef); if (method_exists($hookObj, 'displayWarningMessages_postProcess')) { $hookObj->displayWarningMessages_postProcess($warnings); } } } if (count($warnings)) { if (count($warnings) > 1) { $securityWarnings = '<ul><li>' . implode('</li><li>', $warnings) . '</li></ul>'; } else { $securityWarnings = '<p>' . implode('', $warnings) . '</p>'; } $securityMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $securityWarnings, $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.header'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR); $content = '<div style="margin: 20px 0px;">' . $securityMessage->render() . '</div>'; unset($warnings); return $content; } } return '<p> </p>'; }
/** * If the filename is given, check it against the TYPO3_CONF_VARS[BE][fileDenyPattern] + * Checks if the $ext fileextension is allowed * * @param string $ext File extension, eg. "php" or "html * @param string $_ not in use anymore * @param string $filename Filename to check against TYPO3_CONF_VARS[BE][fileDenyPattern] * @return bool TRUE if extension/filename is allowed * @todo Deprecate, but still in use by DataHandler * @deprecated but still in use in the Core. Don't use in your extensions! */ public function checkIfAllowed($ext, $_, $filename = '') { return GeneralUtility::verifyFilenameAgainstDenyPattern($filename) && $this->is_allowed($ext); }
/** * Tests whether verifyFilenameAgainstDenyPattern detects the NULL character. * * @test */ public function verifyFilenameAgainstDenyPatternDetectsNullCharacter() { $this->assertFalse(Utility\GeneralUtility::verifyFilenameAgainstDenyPattern('image.gif')); }
/** * Checks if fileDenyPattern allows to upload .htaccess files which is * dangerous on Apache. * * @return \TYPO3\CMS\Reports\Status An object representing whether it's possible to upload .htaccess files */ protected function getHtaccessUploadStatus() { $value = $GLOBALS['LANG']->getLL('status_ok'); $message = ''; $severity = \TYPO3\CMS\Reports\Status::OK; if ($GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] != FILE_DENY_PATTERN_DEFAULT && GeneralUtility::verifyFilenameAgainstDenyPattern('.htaccess')) { $value = $GLOBALS['LANG']->getLL('status_insecure'); $severity = \TYPO3\CMS\Reports\Status::ERROR; $message = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:warning.file_deny_htaccess'); } return GeneralUtility::makeInstance('TYPO3\\CMS\\Reports\\Status', $GLOBALS['LANG']->getLL('status_htaccessUploadProtection'), $value, $message, $severity); }
/** * If the fileName is given, checks it against the * TYPO3_CONF_VARS[BE][fileDenyPattern] + and if the file extension is allowed. * * @param string $fileName full filename * @return bool TRUE if extension/filename is allowed */ protected function checkFileExtensionPermission($fileName) { if (!$this->evaluatePermissions) { return true; } $fileName = $this->driver->sanitizeFileName($fileName); $isAllowed = GeneralUtility::verifyFilenameAgainstDenyPattern($fileName); if ($isAllowed) { $fileExtension = strtolower(PathUtility::pathinfo($fileName, PATHINFO_EXTENSION)); // Set up the permissions for the file extension $fileExtensionPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']['webspace']; $fileExtensionPermissions['allow'] = GeneralUtility::uniqueList(strtolower($fileExtensionPermissions['allow'])); $fileExtensionPermissions['deny'] = GeneralUtility::uniqueList(strtolower($fileExtensionPermissions['deny'])); if ($fileExtension !== '') { // If the extension is found amongst the allowed types, we return TRUE immediately if ($fileExtensionPermissions['allow'] === '*' || GeneralUtility::inList($fileExtensionPermissions['allow'], $fileExtension)) { return true; } // If the extension is found amongst the denied types, we return FALSE immediately if ($fileExtensionPermissions['deny'] === '*' || GeneralUtility::inList($fileExtensionPermissions['deny'], $fileExtension)) { return false; } // If no match we return TRUE return true; } else { if ($fileExtensionPermissions['allow'] === '*') { return true; } if ($fileExtensionPermissions['deny'] === '*') { return false; } return true; } } return false; }
/** * Check extension of given filename * * @param string $filename Filename like (upload.png) * @return bool If Extension is allowed */ public static function checkExtension($filename) { $extensionList = 'jpg,jpeg,png,gif,bmp'; if (!empty($GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_femanager.']['settings.']['misc.']['uploadFileExtension'])) { $extensionList = $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_femanager.']['settings.']['misc.']['uploadFileExtension']; $extensionList = str_replace(' ', '', $extensionList); } $fileInfo = pathinfo($filename); if (!empty($fileInfo['extension']) && GeneralUtility::inList($extensionList, strtolower($fileInfo['extension'])) && GeneralUtility::verifyFilenameAgainstDenyPattern($filename) && GeneralUtility::validPathStr($filename)) { return TRUE; } return FALSE; }
/** * Uploads a new avatar to the server. * @author Martin Helmich <*****@*****.**> * @author Georg Ringer <*****@*****.**> * @version 2007-10-03 * @param string $content The plugin content * @return string The content */ function uploadAvatar($content) { $avatarFile = $_FILES[$this->prefixId]; if (isset($this->piVars['del_avatar'])) { $this->user->removeAvatar($this->conf['path_avatar']); $this->user->updateDatabase(); return $content; } $fI = GeneralUtility::split_fileref($avatarFile['name']['file']); $fileExt = $fI['fileext']; if (!GeneralUtility::verifyFilenameAgainstDenyPattern($avatarFile['name']['file']) || !GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExt)) { return ''; } if (isset($this->piVars['upload'])) { $uploaddir = $this->conf['path_avatar']; /* * Load the allowed file size for avatar image from the TCA and * check against the size of the uploaded image. */ if (filesize($avatarFile['tmp_name']['file']) > $GLOBALS['TCA']['fe_users']['columns']['tx_mmforum_avatar']['config']['max_size'] * 1024) { return ''; } $file = $this->user->getUid() . '_' . $GLOBALS['EXEC_TIME'] . '.' . $fileExt; $uploadfile = $uploaddir . $file; if (GeneralUtility::upload_copy_move($avatarFile['tmp_name']['file'], $uploadfile)) { $this->user->setAvatar($file); $this->user->updateDatabase(); } } return $content; }
/** * Makes an upload form for uploading files to the filemount the user is browsing. * The files are uploaded to the tce_file.php script in the core which will handle the upload. * * @param Folder $folderObject * @return string HTML for an upload form. */ public function uploadForm(Folder $folderObject) { if (!$folderObject->checkActionPermission('write')) { return ''; } // Read configuration of upload field count $userSetting = $this->getBackendUser()->getTSConfigVal('options.folderTree.uploadFieldsInLinkBrowser'); $count = isset($userSetting) ? (int) $userSetting : 1; if ($count === 0) { return ''; } $pArr = explode('|', $this->bparams); $allowedExtensions = isset($pArr[3]) ? GeneralUtility::trimExplode(',', $pArr[3], true) : []; $count = (int) $count === 0 ? 1 : (int) $count; // Create header, showing upload path: $header = $folderObject->getIdentifier(); $lang = $this->getLanguageService(); // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc. $fileExtList = array(); foreach ($allowedExtensions as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } $code = ' <br /> <!-- Form, for uploading files: --> <form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" name="editform"' . ' id="typo3-uplFilesForm" enctype="multipart/form-data"> <table border="0" cellpadding="0" cellspacing="0" id="typo3-uplFiles"> <tr> <td>' . $this->barheader($lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.pagetitle', true) . ':') . '</td> </tr> <tr> <td class="c-wCell c-hCell"><strong>' . $lang->getLL('path', true) . ':</strong> ' . htmlspecialchars($header) . '</td> </tr> <tr> <td class="c-wCell c-hCell">'; // Traverse the number of upload fields: $combinedIdentifier = $folderObject->getCombinedIdentifier(); for ($a = 1; $a <= $count; $a++) { $code .= '<input type="file" multiple="multiple" name="upload_' . $a . '[]"' . $this->doc->formWidth(35) . ' size="50" /> <input type="hidden" name="file[upload][' . $a . '][target]" value="' . htmlspecialchars($combinedIdentifier) . '" /> <input type="hidden" name="file[upload][' . $a . '][data]" value="' . $a . '" /><br />'; } // Make footer of upload form, including the submit button: $redirectValue = $this->getThisScript() . 'act=' . $this->act . '&mode=' . $this->mode . '&expandFolder=' . rawurlencode($combinedIdentifier) . '&bparams=' . rawurlencode($this->bparams) . (is_array($this->P) ? GeneralUtility::implodeArrayForUrl('P', $this->P) : ''); $code .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />'; if (!empty($fileExtList)) { $code .= ' <div class="help-block"> ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:cm.allowedFileExtensions', true) . '<br> ' . implode(' ', $fileExtList) . ' </div> '; } $code .= ' <div id="c-override"> <label> <input type="checkbox" name="overwriteExistingFiles" id="overwriteExistingFiles" value="1" /> ' . $lang->sL('LLL:EXT:lang/locallang_misc.xlf:overwriteExistingFiles', true) . ' </label> </div> <input class="btn btn-default" type="submit" name="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.submit', true) . '" /> '; $code .= '</td> </tr> </table> </form>'; // Add online media // Create a list of allowed file extensions in a readable format "youtube, vimeo" etc. $fileExtList = array(); $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions(); foreach ($onlineMediaFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt) && (empty($allowedExtensions) || in_array($fileExt, $allowedExtensions, true))) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } if (!empty($fileExtList)) { $code .= ' <!-- Form, adding online media urls: --> <form action="' . htmlspecialchars(BackendUtility::getModuleUrl('online_media')) . '" method="post" name="editform1"' . ' id="typo3-addMediaForm"> <table border="0" cellpadding="0" cellspacing="0" id="typo3-uplFiles"> <tr> <td>' . $this->barheader($lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media', true) . ':') . '</td> </tr> <tr> <td class="c-wCell c-hCell"><strong>' . $lang->getLL('path', true) . ':</strong> ' . htmlspecialchars($header) . '</td> </tr> <tr> <td class="c-wCell c-hCell"> <input type="text" name="file[newMedia][0][url]"' . $this->doc->formWidth(35) . ' size="50" placeholder="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.placeholder', true) . '" /> <input type="hidden" name="file[newMedia][0][target]" value="' . htmlspecialchars($folderObject->getCombinedIdentifier()) . '" /> <input type="hidden" name="file[newMedia][0][allowed]" value="' . htmlspecialchars(implode(',', $allowedExtensions)) . '" /> <button>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.submit', true) . '</button> <div class="help-block"> ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.allowedProviders') . '<br> ' . implode(' ', $fileExtList) . ' </div> '; } // Make footer of upload form, including the submit button: $redirectValue = $this->getThisScript() . 'act=' . $this->act . '&mode=' . $this->mode . '&expandFolder=' . rawurlencode($folderObject->getCombinedIdentifier()) . '&bparams=' . rawurlencode($this->bparams) . (is_array($this->P) ? GeneralUtility::implodeArrayForUrl('P', $this->P) : ''); $code .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />'; $code .= '</td> </tr> </table> </form><br />'; return $code; }
/** * Import a resource and respect configuration given for properties * * @param array $uploadInfo * @param PropertyMappingConfigurationInterface $configuration * @return ExtbaseFileReference * @throws TypeConverterException */ protected function importUploadedResource(array $uploadInfo, PropertyMappingConfigurationInterface $configuration) : ExtbaseFileReference { if (!GeneralUtility::verifyFilenameAgainstDenyPattern($uploadInfo['name'])) { throw new TypeConverterException('Uploading files with PHP file extensions is not allowed!', 1471710357); } $uploadFolderId = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_UPLOAD_FOLDER) ?: $this->defaultUploadFolder; $conflictMode = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_UPLOAD_CONFLICT_MODE) ?: $this->defaultConflictMode; $uploadFolder = $this->resourceFactory->retrieveFileOrFolderObject($uploadFolderId); $uploadedFile = $uploadFolder->addUploadedFile($uploadInfo, $conflictMode); $validators = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_FILE_VALIDATORS); if (is_array($validators)) { foreach ($validators as $validator) { if ($validator instanceof AbstractValidator) { $validationResult = $validator->validate($uploadedFile); if ($validationResult->hasErrors()) { $uploadedFile->getStorage()->deleteFile($uploadedFile); throw new TypeConverterException($validationResult->getErrors()[0]->getMessage(), 1471708999); } } } } $resourcePointer = isset($uploadInfo['submittedFile']['resourcePointer']) && strpos($uploadInfo['submittedFile']['resourcePointer'], 'file:') === false ? $this->hashService->validateAndStripHmac($uploadInfo['submittedFile']['resourcePointer']) : null; $fileReferenceModel = $this->createFileReferenceFromFalFileObject($uploadedFile, $resourcePointer); return $fileReferenceModel; }
/** * Main function, rendering the main module content * * @return void */ public function main() { $lang = $this->getLanguageService(); $assigns = []; $assigns['target'] = $this->target; if ($this->folderObject->checkActionPermission('add')) { $assigns['moduleUrlTceFile'] = BackendUtility::getModuleUrl('tce_file'); $assigns['cshFileNewFolder'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder'); // Making the selector box for the number of concurrent folder-creations $this->number = MathUtility::forceIntegerInRange($this->number, 1, 10); for ($a = 1; $a <= $this->folderNumber; $a++) { $options = []; $options['value'] = $a; $options['selected'] = $this->number == $a ? ' selected="selected"' : ''; $assigns['options'][] = $options; } // Making the number of new-folder boxes needed: for ($a = 0; $a < $this->number; $a++) { $folder = []; $folder['this'] = $a; $folder['next'] = $a + 1; $assigns['folders'][] = $folder; } // Making submit button for folder creation: $assigns['returnUrl'] = $this->returnUrl; } if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) { $assigns['moduleUrlOnlineMedia'] = BackendUtility::getModuleUrl('online_media'); $assigns['cshFileNewMedia'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia'); // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc. $fileExtList = []; $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions(); foreach ($onlineMediaFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) { $fileExtList[] = strtoupper(htmlspecialchars($fileExt)); } } $assigns['fileExtList'] = $fileExtList; $assigns['moduleUrlTceFile'] = BackendUtility::getModuleUrl('tce_file'); $assigns['cshFileNewFile'] = BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile'); // Create a list of allowed file extensions with a text format "*.txt, *.css" etc. $fileExtList = []; $textFileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], true); foreach ($textFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern('.' . $fileExt)) { $fileExtList[] = strtoupper(htmlspecialchars($fileExt)); } } $assigns['txtFileExtList'] = $fileExtList; } $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar(); // Back if ($this->returnUrl) { $backButton = $buttonBar->makeLinkButton()->setHref($this->returnUrl)->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.goBack'))->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL)); $buttonBar->addButton($backButton); } // Rendering of the output via fluid $view = GeneralUtility::makeInstance(StandaloneView::class); $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]); $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]); $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/File/CreateFolder.html')); $view->assignMultiple($assigns); $this->content = $view->render(); $this->moduleTemplate->setContent($this->content); }
/** * Sends a header "Location" to jumpUrl, if jumpurl is set. * Will exit if a location header is sent (for instance if jumpUrl was triggered) * * "jumpUrl" is a concept where external links are redirected from the index_ts.php script, which first logs the URL. * * @return void * @todo Define visibility */ public function jumpUrl() { if ($this->jumpurl) { if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('juSecure')) { $locationData = (string) \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('locationData'); // Need a type cast here because mimeType is optional! $mimeType = (string) \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('mimeType'); $hArr = array($this->jumpurl, $locationData, $mimeType); $calcJuHash = \TYPO3\CMS\Core\Utility\GeneralUtility::hmac(serialize($hArr)); $juHash = (string) \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('juHash'); if ($juHash === $calcJuHash) { if ($this->locDataCheck($locationData)) { // 211002 - goes with cObj->filelink() rawurlencode() of filenames so spaces can be allowed. $this->jumpurl = rawurldecode($this->jumpurl); // Deny access to files that match TYPO3_CONF_VARS[SYS][fileDenyPattern] and whose parent directory is typo3conf/ (there could be a backup file in typo3conf/ which does not match against the fileDenyPattern) $absoluteFileName = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName(\TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($this->jumpurl), FALSE); if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath($absoluteFileName) && \TYPO3\CMS\Core\Utility\GeneralUtility::verifyFilenameAgainstDenyPattern($absoluteFileName) && !\TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($absoluteFileName, PATH_site . 'typo3conf')) { if (@is_file($absoluteFileName)) { $mimeType = $mimeType ? $mimeType : 'application/octet-stream'; header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-Type: ' . $mimeType); header('Content-Disposition: attachment; filename="' . basename($absoluteFileName) . '"'); readfile($absoluteFileName); die; } else { throw new \Exception('jumpurl Secure: "' . $this->jumpurl . '" was not a valid file!', 1294585193); } } else { throw new \Exception('jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!', 1294585194); } } else { throw new \Exception('jumpurl Secure: locationData, ' . $locationData . ', was not accessible.', 1294585195); } } else { throw new \Exception('jumpurl Secure: Calculated juHash did not match the submitted juHash.', 1294585196); } } else { $TSConf = $this->getPagesTSconfig(); if ($TSConf['TSFE.']['jumpUrl_transferSession']) { $uParts = parse_url($this->jumpurl); $params = '&FE_SESSION_KEY=' . rawurlencode($this->fe_user->id . '-' . md5($this->fe_user->id . '/' . $this->TYPO3_CONF_VARS['SYS']['encryptionKey'])); // Add the session parameter ... $this->jumpurl .= ($uParts['query'] ? '' : '?') . $params; } if ($TSConf['TSFE.']['jumpURL_HTTPStatusCode']) { switch (intval($TSConf['TSFE.']['jumpURL_HTTPStatusCode'])) { case 301: $statusCode = \TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_301; break; case 302: $statusCode = \TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_302; break; case 307: $statusCode = \TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_307; break; case 303: default: $statusCode = \TYPO3\CMS\Core\Utility\HttpUtility::HTTP_STATUS_303; break; } } \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->jumpurl, $statusCode); } } }
/** * Checks the input string (un-parsed TypoScript) for include-commands ("<INCLUDE_TYPOSCRIPT: ....") * Use: t3lib_TSparser::checkIncludeLines() * * @param string $string Unparsed TypoScript * @param integer $cycle_counter Counter for detecting endless loops * @param boolean $returnFiles When set an array containing the resulting typoscript and all included files will get returned * @return string Complete TypoScript with includes added. * @static */ public static function checkIncludeLines($string, $cycle_counter = 1, $returnFiles = FALSE) { $includedFiles = array(); if ($cycle_counter > 100) { \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_WARNING); if ($returnFiles) { return array('typoscript' => '', 'files' => $includedFiles); } return ' ### ### ERROR: Recursion! ### '; } $splitStr = '<INCLUDE_TYPOSCRIPT:'; if (strstr($string, $splitStr)) { $newString = ''; // Adds line break char before/after $allParts = explode($splitStr, LF . $string . LF); foreach ($allParts as $c => $v) { // First goes through if (!$c) { $newString .= $v; } elseif (preg_match('/\\r?\\n\\s*$/', $allParts[$c - 1])) { $subparts = explode('>', $v, 2); // There must be a line-break char after if (preg_match('/^\\s*\\r?\\n/', $subparts[1])) { // SO, the include was positively recognized: $newString .= '### ' . $splitStr . $subparts[0] . '> BEGIN:' . LF; $params = \TYPO3\CMS\Core\Utility\GeneralUtility::get_tag_attributes($subparts[0]); if ($params['source']) { $sourceParts = explode(':', $params['source'], 2); switch (strtolower(trim($sourceParts[0]))) { case 'file': $filename = \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName(trim($sourceParts[1])); // Must exist and must not contain '..' and must be relative if (strcmp($filename, '')) { // Check for allowed files if (\TYPO3\CMS\Core\Utility\GeneralUtility::verifyFilenameAgainstDenyPattern($filename)) { if (@is_file($filename)) { // Check for includes in included text $includedFiles[] = $filename; $included_text = self::checkIncludeLines(\TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($filename), $cycle_counter + 1, $returnFiles); // If the method also has to return all included files, merge currently included // files with files included by recursively calling itself if ($returnFiles && is_array($included_text)) { $includedFiles = array_merge($includedFiles, $included_text['files']); $included_text = $included_text['typoscript']; } $newString .= $included_text . LF; } else { $newString .= ' ### ### ERROR: File "' . $filename . '" was not was not found. ### '; \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('File "' . $filename . '" was not found.', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_WARNING); } } else { $newString .= ' ### ### ERROR: File "' . $filename . '" was not included since it is not allowed due to fileDenyPattern ### '; \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('File "' . $filename . '" was not included since it is not allowed due to fileDenyPattern', 'Core', \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_WARNING); } } break; } } $newString .= '### ' . $splitStr . $subparts[0] . '> END:' . LF; $newString .= $subparts[1]; } else { $newString .= $splitStr . $v; } } else { $newString .= $splitStr . $v; } } // Not the first/last linebreak char. $string = substr($newString, 1, -1); } // When all included files should get returned, simply return an compound array containing // the TypoScript with all "includes" processed and the files which got included if ($returnFiles) { return array('typoscript' => $string, 'files' => $includedFiles); } return $string; }
/** * Search for commented INCLUDE_TYPOSCRIPT statements * and save the content between the BEGIN and the END line to the specified file * * @param string $string Template content * @param int $cycle_counter Counter for detecting endless loops * @param array $extractedFileNames * @param string $parentFilenameOrPath * * @throws \RuntimeException * @throws \UnexpectedValueException * @return string Template content with uncommented include statements */ public static function extractIncludes($string, $cycle_counter = 1, array $extractedFileNames = array(), $parentFilenameOrPath = '') { if ($cycle_counter > 10) { GeneralUtility::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags', 'Core', GeneralUtility::SYSLOG_SEVERITY_WARNING); return ' ### ### ERROR: Recursion! ### '; } $expectedEndTag = ''; $fileContent = array(); $restContent = array(); $fileName = NULL; $inIncludePart = FALSE; $lines = preg_split("/\r\n|\n|\r/", $string); $skipNextLineIfEmpty = FALSE; $openingCommentedIncludeStatement = NULL; $optionalProperties = ''; foreach ($lines as $line) { // \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::checkIncludeLines inserts // an additional empty line, remove this again if ($skipNextLineIfEmpty) { if (trim($line) === '') { continue; } $skipNextLineIfEmpty = FALSE; } // Outside commented include statements if (!$inIncludePart) { // Search for beginning commented include statements if (preg_match('/###\\s*<INCLUDE_TYPOSCRIPT:\\s*source\\s*=\\s*"\\s*((?i)file|dir)\\s*:\\s*([^"]*)"(.*)>\\s*BEGIN/i', $line, $matches)) { // Found a commented include statement // Save this line in case there is no ending tag $openingCommentedIncludeStatement = trim($line); $openingCommentedIncludeStatement = preg_replace('/\\s*### Warning: .*###\\s*/', '', $openingCommentedIncludeStatement); // type of match: FILE or DIR $inIncludePart = strtoupper($matches[1]); $fileName = $matches[2]; $optionalProperties = $matches[3]; $expectedEndTag = '### <INCLUDE_TYPOSCRIPT: source="' . $inIncludePart . ':' . $fileName . '"' . $optionalProperties . '> END'; // Strip all whitespace characters to make comparison safer $expectedEndTag = strtolower(preg_replace('/\\s/', '', $expectedEndTag)); } else { // If this is not a beginning commented include statement this line goes into the rest content $restContent[] = $line; } //if (is_array($matches)) GeneralUtility::devLog('matches', 'TypoScriptParser', 0, $matches); } else { // Inside commented include statements // Search for the matching ending commented include statement $strippedLine = preg_replace('/\\s/', '', $line); if (stripos($strippedLine, $expectedEndTag) !== FALSE) { // Found the matching ending include statement $fileContentString = implode(PHP_EOL, $fileContent); // Write the content to the file // Resolve a possible relative paths if a parent file is given if ($parentFilenameOrPath !== '' && $fileName[0] === '.') { $realFileName = PathUtility::getAbsolutePathOfRelativeReferencedFileOrPath($parentFilenameOrPath, $fileName); } else { $realFileName = $fileName; } $realFileName = GeneralUtility::getFileAbsFileName($realFileName); if ($inIncludePart === 'FILE') { // Some file checks if (!GeneralUtility::verifyFilenameAgainstDenyPattern($realFileName)) { throw new \UnexpectedValueException(sprintf('File "%s" was not included since it is not allowed due to fileDenyPattern.', $fileName), 1382651858); } if (empty($realFileName)) { throw new \UnexpectedValueException(sprintf('"%s" is not a valid file location.', $fileName), 1294586441); } if (!is_writable($realFileName)) { throw new \RuntimeException(sprintf('"%s" is not writable.', $fileName), 1294586442); } if (in_array($realFileName, $extractedFileNames)) { throw new \RuntimeException(sprintf('Recursive/multiple inclusion of file "%s"', $realFileName), 1294586443); } $extractedFileNames[] = $realFileName; // Recursive call to detected nested commented include statements $fileContentString = self::extractIncludes($fileContentString, $cycle_counter + 1, $extractedFileNames, $realFileName); // Write the content to the file if (!GeneralUtility::writeFile($realFileName, $fileContentString)) { throw new \RuntimeException(sprintf('Could not write file "%s"', $realFileName), 1294586444); } // Insert reference to the file in the rest content $restContent[] = '<INCLUDE_TYPOSCRIPT: source="FILE:' . $fileName . '"' . $optionalProperties . '>'; } else { // must be DIR // Some file checks if (empty($realFileName)) { throw new \UnexpectedValueException(sprintf('"%s" is not a valid location.', $fileName), 1366493602); } if (!is_dir($realFileName)) { throw new \RuntimeException(sprintf('"%s" is not a directory.', $fileName), 1366493603); } if (in_array($realFileName, $extractedFileNames)) { throw new \RuntimeException(sprintf('Recursive/multiple inclusion of directory "%s"', $realFileName), 1366493604); } $extractedFileNames[] = $realFileName; // Recursive call to detected nested commented include statements self::extractIncludes($fileContentString, $cycle_counter + 1, $extractedFileNames, $realFileName); // just drop content between tags since it should usually just contain individual files from that dir // Insert reference to the dir in the rest content $restContent[] = '<INCLUDE_TYPOSCRIPT: source="DIR:' . $fileName . '"' . $optionalProperties . '>'; } // Reset variables (preparing for the next commented include statement) $fileContent = array(); $fileName = NULL; $inIncludePart = FALSE; $openingCommentedIncludeStatement = NULL; // \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::checkIncludeLines inserts // an additional empty line, remove this again $skipNextLineIfEmpty = TRUE; } else { // If this is not a ending commented include statement this line goes into the file content $fileContent[] = $line; } } } // If we're still inside commented include statements copy the lines back to the rest content if ($inIncludePart) { $restContent[] = $openingCommentedIncludeStatement . ' ### Warning: Corresponding end line missing! ###'; $restContent = array_merge($restContent, $fileContent); } $restContentString = implode(PHP_EOL, $restContent); return $restContentString; }
/** * Is file-extension allowed for uploading? * * @param string $filename Filename like (upload_03.txt) * @param string $fileExtensions allowed file extensions * @return bool */ public static function checkExtension($filename, $fileExtensions = '') { $fileInfo = pathinfo($filename); if (!empty($fileInfo['extension']) && !empty($fileExtensions) && GeneralUtility::inList($fileExtensions, $fileInfo['extension']) && GeneralUtility::verifyFilenameAgainstDenyPattern($filename) && GeneralUtility::validPathStr($filename)) { return true; } return false; }
/** * If the submitted hash is correct and the user has access to the * related content element the contents of the submitted file will * be output to the user. * * @param string $jumpUrl The URL to the file that should be output to the user * @throws \Exception */ protected function forwardJumpUrlSecureFileData($jumpUrl) { // Set the parameters required for handling a secure jumpUrl link // The locationData GET parameter, containing information about the record that created the URL $locationData = (string) GeneralUtility::_GP('locationData'); // The optional mimeType GET parameter $mimeType = (string) GeneralUtility::_GP('mimeType'); // The jump Url Hash GET parameter $juHash = (string) GeneralUtility::_GP('juHash'); // validate the hash GET parameter against the other parameters if ($juHash !== JumpUrlUtility::calculateHashSecure($jumpUrl, $locationData, $mimeType)) { throw new \Exception('The calculated Jump URL secure hash ("juHash") did not match the submitted "juHash" query parameter.', 1294585196); } if (!$this->isLocationDataValid($locationData)) { throw new \Exception('The calculated secure location data "' . $locationData . '" is not accessible.', 1294585195); } // Allow spaces / special chars in filenames. $jumpUrl = rawurldecode($jumpUrl); // Deny access to files that match TYPO3_CONF_VARS[SYS][fileDenyPattern] and whose parent directory // is typo3conf/ (there could be a backup file in typo3conf/ which does not match against the fileDenyPattern) $absoluteFileName = GeneralUtility::getFileAbsFileName(GeneralUtility::resolveBackPath($jumpUrl), false); if (!GeneralUtility::isAllowedAbsPath($absoluteFileName) || !GeneralUtility::verifyFilenameAgainstDenyPattern($absoluteFileName) || GeneralUtility::isFirstPartOfStr($absoluteFileName, PATH_site . 'typo3conf')) { throw new \Exception('The requested file was not allowed to be accessed through Jump URL. The path or file is not allowed.', 1294585194); } try { $resourceFactory = $this->getResourceFactory(); $file = $resourceFactory->retrieveFileOrFolderObject($absoluteFileName); $this->readFileAndExit($file, $mimeType); } catch (\Exception $e) { throw new \Exception('The requested file "' . $jumpUrl . '" for Jump URL was not found..', 1294585193); } }
/** * Makes an upload form for uploading files to the filemount the user is browsing. * The files are uploaded to the tce_file.php script in the core which will handle the upload. * * @param Folder $folderObject * @param string[] $allowedExtensions * * @return string HTML for an upload form. */ public function uploadForm(Folder $folderObject, array $allowedExtensions) { if (!$folderObject->checkActionPermission('write')) { return ''; } // Read configuration of upload field count $userSetting = $this->getBackendUser()->getTSConfigVal('options.folderTree.uploadFieldsInLinkBrowser'); $count = isset($userSetting) ? (int) $userSetting : 1; if ($count === 0) { return ''; } $count = (int) $count === 0 ? 1 : (int) $count; // Create header, showing upload path: $header = $folderObject->getIdentifier(); $lang = $this->getLanguageService(); // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc. $fileExtList = array(); foreach ($allowedExtensions as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } $formAction = BackendUtility::getModuleUrl('tce_file'); $combinedIdentifier = $folderObject->getCombinedIdentifier(); $markup = array(); $markup[] = '<div class="element-browser-section element-browser-upload">'; $markup[] = ' <form action="' . htmlspecialchars($formAction) . '" method="post" name="editform" enctype="multipart/form-data">'; $markup[] = ' <h3>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.pagetitle', true) . ':</h3>'; $markup[] = ' <p><strong>' . $lang->getLL('path', true) . ':</strong>' . htmlspecialchars($header) . '</p>'; // Traverse the number of upload fields: for ($a = 1; $a <= $count; $a++) { $markup[] = '<div class="form-group">'; $markup[] = '<span class="btn btn-default btn-file">'; $markup[] = '<input type="file" multiple="multiple" name="upload_' . $a . '[]" size="50" />'; $markup[] = '</span>'; $markup[] = '</div>'; $markup[] = '<input type="hidden" name="file[upload][' . $a . '][target]" value="' . htmlspecialchars($combinedIdentifier) . '" />'; $markup[] = '<input type="hidden" name="file[upload][' . $a . '][data]" value="' . $a . '" />'; } $redirectValue = $this->parameterProvider->getScriptUrl() . GeneralUtility::implodeArrayForUrl('', $this->parameterProvider->getUrlParameters(['identifier' => $combinedIdentifier])); $markup[] = '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />'; if (!empty($fileExtList)) { $markup[] = '<div class="form-group">'; $markup[] = ' <label>'; $markup[] = $lang->sL('LLL:EXT:lang/locallang_core.xlf:cm.allowedFileExtensions', true) . '<br/>'; $markup[] = ' </label>'; $markup[] = ' <div class="form-control">'; $markup[] = implode(' ', $fileExtList); $markup[] = ' </div>'; $markup[] = '</div>'; } $markup[] = '<div class="checkbox">'; $markup[] = ' <label>'; $markup[] = ' <input type="checkbox" name="overwriteExistingFiles" id="overwriteExistingFiles" value="1" />'; $markup[] = $lang->sL('LLL:EXT:lang/locallang_misc.xlf:overwriteExistingFiles', true); $markup[] = ' </label>'; $markup[] = '</div>'; $markup[] = '<input class="btn btn-default" type="submit" name="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.submit', true) . '" />'; $markup[] = ' </form>'; $markup[] = '</div>'; $code = implode(LF, $markup); // Add online media // Create a list of allowed file extensions in a readable format "youtube, vimeo" etc. $fileExtList = array(); $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions(); foreach ($onlineMediaFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt) && (empty($allowedExtensions) || in_array($fileExt, $allowedExtensions, true))) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } if (!empty($fileExtList)) { $formAction = BackendUtility::getModuleUrl('online_media'); $markup = array(); $markup[] = '<div class="element-browser-section element-browser-mediaurls">'; $markup[] = ' <form action="' . htmlspecialchars($formAction) . '" method="post" name="editform1" id="typo3-addMediaForm" enctype="multipart/form-data">'; $markup[] = '<h3>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media', true) . ':</h3>'; $markup[] = '<p><strong>' . $lang->getLL('path', true) . ':</strong>' . htmlspecialchars($header) . '</p>'; $markup[] = '<div class="form-group">'; $markup[] = '<input type="hidden" name="file[newMedia][0][target]" value="' . htmlspecialchars($folderObject->getCombinedIdentifier()) . '" />'; $markup[] = '<input type="hidden" name="file[newMedia][0][allowed]" value="' . htmlspecialchars(implode(',', $allowedExtensions)) . '" />'; $markup[] = '<input type="text" name="file[newMedia][0][url]" class="form-control" placeholder="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.placeholder', true) . '" />'; $markup[] = '<button class="btn btn-default">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.submit', true) . '</button>'; $markup[] = '</div>'; $markup[] = '<div class="form-group">'; $markup[] = ' <label>'; $markup[] = $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.allowedProviders') . '<br/>'; $markup[] = ' </label>'; $markup[] = ' <div class="form-control">'; $markup[] = implode(' ', $fileExtList); $markup[] = ' </div>'; $markup[] = '</div>'; $markup[] = '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />'; $markup[] = '</div>'; $markup[] = '</form>'; $markup[] = '</div>'; $code .= implode(LF, $markup); } return $code; }
/** * If the fileName is given, check it against the * TYPO3_CONF_VARS[BE][fileDenyPattern] + and if the file extension is allowed * * @param string $fileName Full filename * @return boolean TRUE if extension/filename is allowed */ protected function checkFileExtensionPermission($fileName) { $isAllowed = \TYPO3\CMS\Core\Utility\GeneralUtility::verifyFilenameAgainstDenyPattern($fileName); if ($isAllowed) { $fileInfo = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($fileName); // Set up the permissions for the file extension $fileExtensionPermissions = $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']['webspace']; $fileExtensionPermissions['allow'] = \TYPO3\CMS\Core\Utility\GeneralUtility::uniqueList(strtolower($fileExtensionPermissions['allow'])); $fileExtensionPermissions['deny'] = \TYPO3\CMS\Core\Utility\GeneralUtility::uniqueList(strtolower($fileExtensionPermissions['deny'])); $fileExtension = strtolower($fileInfo['fileext']); if ($fileExtension !== '') { // If the extension is found amongst the allowed types, we return TRUE immediately if ($fileExtensionPermissions['allow'] === '*' || \TYPO3\CMS\Core\Utility\GeneralUtility::inList($fileExtensionPermissions['allow'], $fileExtension)) { return TRUE; } // If the extension is found amongst the denied types, we return FALSE immediately if ($fileExtensionPermissions['deny'] === '*' || \TYPO3\CMS\Core\Utility\GeneralUtility::inList($fileExtensionPermissions['deny'], $fileExtension)) { return FALSE; } // If no match we return TRUE return TRUE; } else { if ($fileExtensionPermissions['allow'] === '*') { return TRUE; } if ($fileExtensionPermissions['deny'] === '*') { return FALSE; } return TRUE; } } return FALSE; }
/** * If the filename is given, check it against the TYPO3_CONF_VARS[BE][fileDenyPattern] + * Checks if the $ext fileextension is allowed in the path $theDest (this is based on whether $theDest is below the $this->webPath) * * @param string File extension, eg. "php" or "html * @param string Absolute path for which to test * @param string Filename to check against TYPO3_CONF_VARS[BE][fileDenyPattern] * @return bool TRUE if extension/filename is allowed * @todo Deprecate, but still in use by DataHandler * @deprecated but still in use in the Core. Don't use in your extensions! */ public function checkIfAllowed($ext, $theDest, $filename = '') { return GeneralUtility::verifyFilenameAgainstDenyPattern($filename) && $this->is_allowed($ext, $this->is_webpath($theDest) ? 'webspace' : 'ftpspace'); }
/** * Main function, rendering the main module content * * @return void */ public function main() { $lang = $this->getLanguageService(); $pageContent = '<h1>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle') . '</h1>'; if ($this->folderObject->checkActionPermission('add')) { $code = '<form role="form" action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" name="editform">'; // Making the selector box for the number of concurrent folder-creations $this->number = MathUtility::forceIntegerInRange($this->number, 1, 10); $code .= ' <div class="form-group"> <div class="form-section"> <div class="form-group"> <label for="number-of-new-folders">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.number_of_folders') . '</label> ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfolder') . ' <div class="form-control-wrap"> <div class="input-group"> <select class="form-control form-control-adapt" name="number" id="number-of-new-folders" onchange="reload(this.options[this.selectedIndex].value);">'; for ($a = 1; $a <= $this->folderNumber; $a++) { $code .= '<option value="' . $a . '"' . ($this->number == $a ? ' selected="selected"' : '') . '>' . $a . '</option>'; } $code .= ' </select> </div> </div> </div> </div> '; // Making the number of new-folder boxes needed: for ($a = 0; $a < $this->number; $a++) { $code .= ' <div class="form-section"> <div class="form-group"> <label for="folder_new_' . $a . '">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.label_newfolder') . ' ' . ($a + 1) . ':</label> <div class="form-control-wrap"> <input type="text" class="form-control" id="folder_new_' . $a . '" name="file[newfolder][' . $a . '][data]" onchange="changed=true;" /> <input type="hidden" name="file[newfolder][' . $a . '][target]" value="' . htmlspecialchars($this->target) . '" /> </div> </div> </div>'; } // Making submit button for folder creation: $code .= ' </div><div class="form-group"> <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.submit', true) . '" /> <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" /> </div> '; // Switching form tags: $pageContent .= '<h3>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfolders', true) . '</h3>'; $pageContent .= '<div>' . $code . '</form></div>'; } if ($this->folderObject->getStorage()->checkUserActionPermission('add', 'File')) { $pageContent .= '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('online_media')) . '" method="post" name="editform2">'; // Create a list of allowed file extensions with the readable format "youtube, vimeo" etc. $fileExtList = array(); $onlineMediaFileExt = OnlineMediaHelperRegistry::getInstance()->getSupportedFileExtensions(); foreach ($onlineMediaFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } // Add form fields for adding media files: $code = ' <div class="form-group"> <div class="form-section"> <div class="form-group"> <label for="newMedia">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.label', true) . '</label> ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newMedia') . ' <div class="form-control-wrap"> <input class="form-control" type="text" id="newMedia" name="file[newMedia][0][url]" placeholder="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.placeholder', true) . '" /> <input type="hidden" name="file[newMedia][0][target]" value="' . htmlspecialchars($this->target) . '" /> </div> <div class="help-block"> ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.allowedProviders', true) . '<br> ' . implode(' ', $fileExtList) . ' </div> </div> </div> </div> '; // Submit button for creation of a new media: $code .= ' <div class="form-group"> <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media.submit', true) . '" /> <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" /> </div> '; $pageContent .= '<h3>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:online_media.new_media', true) . '</h3>'; $pageContent .= '<div>' . $code . '</div>'; $pageContent .= '</form>'; $pageContent .= '<form action="' . BackendUtility::getModuleUrl('tce_file') . '" method="post" name="editform3">'; // Create a list of allowed file extensions with the nice format "*.jpg, *.gif" etc. $fileExtList = array(); $textFileExt = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], true); foreach ($textFileExt as $fileExt) { if (GeneralUtility::verifyFilenameAgainstDenyPattern($fileExt)) { $fileExtList[] = '<span class="label label-success">' . strtoupper(htmlspecialchars($fileExt)) . '</span>'; } } // Add form fields for creation of a new, blank text file: $code = ' <div class="form-group"> <div class="form-section"> <div class="form-group"> <label for="newfile">' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.label_newfile', true) . '</label> ' . BackendUtility::cshItem('xMOD_csh_corebe', 'file_newfile') . ' <div class="form-control-wrap"> <input class="form-control" type="text" id="newfile" name="file[newfile][0][data]" onchange="changed=true;" /> <input type="hidden" name="file[newfile][0][target]" value="' . htmlspecialchars($this->target) . '" /> </div> <div class="help-block"> ' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:cm.allowedFileExtensions', true) . '<br> ' . implode(' ', $fileExtList) . ' </div> </div> </div> </div> '; // Submit button for creation of a new file: $code .= ' <div class="form-group"> <input class="btn btn-default" type="submit" value="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile_submit', true) . '" /> <input type="hidden" name="redirect" value="' . htmlspecialchars($this->returnUrl) . '" /> </div> '; $pageContent .= '<h3>' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.newfile', true) . '</h3>'; $pageContent .= '<div>' . $code . '</div>'; $pageContent .= '</form>'; } $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar(); // Back if ($this->returnUrl) { $backButton = $buttonBar->makeLinkButton()->setHref(GeneralUtility::linkThisUrl($this->returnUrl))->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack'))->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL)); $buttonBar->addButton($backButton); } $this->content .= '<div>' . $pageContent . '</div>'; $this->moduleTemplate->setContent($this->content); }
/** * Processing of files. * NOTICE: for now files can be handled only on creation of records. But a more advanced feature is that PREVIEW of files is handled. * * @param array $cmdParts Array with cmd-parts (from parseValues()). This will for example contain information about allowed file extensions and max size of uploaded files. * @param string $theField The fieldname with the files. * * @return void * @see parseValues() */ protected function processFiles($cmdParts, $theField) { // First, make an array with the filename and file reference, whether the file is just uploaded or a preview $filesArr = []; if (is_string($this->dataArr[$theField])) { // files from preview. $tmpArr = explode(',', $this->dataArr[$theField]); foreach ($tmpArr as $val) { $valParts = explode('|', $val); $filesArr[] = ['name' => $valParts[1], 'tmp_name' => PATH_site . 'typo3temp/' . $valParts[0]]; } } elseif (is_array($_FILES['FE'][$this->theTable][$theField]['name'])) { // Files from upload foreach ($_FILES['FE'][$this->theTable][$theField]['name'] as $kk => $vv) { if ($vv) { $tmpFile = GeneralUtility::upload_to_tempfile($_FILES['FE'][$this->theTable][$theField]['tmp_name'][$kk]); if ($tmpFile) { $this->unlinkTempFiles[] = $tmpFile; $filesArr[] = ['name' => $vv, 'tmp_name' => $tmpFile]; } } } } elseif (is_array($_FILES['FE']['name'][$this->theTable][$theField])) { // Files from upload foreach ($_FILES['FE']['name'][$this->theTable][$theField] as $kk => $vv) { if ($vv) { $tmpFile = GeneralUtility::upload_to_tempfile($_FILES['FE']['tmp_name'][$this->theTable][$theField][$kk]); if ($tmpFile) { $this->unlinkTempFiles[] = $tmpFile; $filesArr[] = ['name' => $vv, 'tmp_name' => $tmpFile]; } } } } // Then verify the files in that array; check existence, extension and size $this->dataArr[$theField] = ''; $finalFilesArr = []; if (count($filesArr)) { $extArray = GeneralUtility::trimExplode(';', strtolower($cmdParts[1]), 1); $maxSize = intval($cmdParts[3]); foreach ($filesArr as $infoArr) { $fI = pathinfo($infoArr['name']); if (GeneralUtility::verifyFilenameAgainstDenyPattern($fI['name'])) { if (!count($extArray) || in_array(strtolower($fI['extension']), $extArray)) { $tmpFile = $infoArr['tmp_name']; if (@is_file($tmpFile)) { if (!$maxSize || filesize($tmpFile) < $maxSize * 1024) { $finalFilesArr[] = $infoArr; } elseif ($this->conf['debug']) { debug('Size is beyond ' . $maxSize . ' kb (' . filesize($tmpFile) . ' bytes) and the file cannot be saved.'); } } elseif ($this->conf['debug']) { debug('Surprisingly there was no file for ' . $vv . ' in ' . $tmpFile); } } elseif ($this->conf['debug']) { debug('Extension "' . $fI['extension'] . '" not allowed'); } } elseif ($this->conf['debug']) { debug('Filename matched illegal pattern.'); } } } // Copy the files in the resulting array to the proper positions based on preview/non-preview. $fileNameList = []; $uploadPath = ''; foreach ($finalFilesArr as $infoArr) { if ($this->isPreview()) { // If the form is a preview form (and data is therefore not going into the database...) do this. $this->createFileFuncObj(); $fI = pathinfo($infoArr['name']); $tmpFilename = $this->theTable . '_' . GeneralUtility::shortmd5(uniqid($infoArr['name'])) . '.' . $fI['extension']; $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($tmpFilename), PATH_site . 'typo3temp/'); GeneralUtility::upload_copy_move($infoArr['tmp_name'], $theDestFile); // Setting the filename in the list $fI2 = pathinfo($theDestFile); $fileNameList[] = $fI2['basename'] . '|' . $infoArr['name']; } else { $this->createFileFuncObj(); if (is_array($GLOBALS['TCA'][$this->theTable]['columns'][$theField])) { $uploadPath = $GLOBALS['TCA'][$this->theTable]['columns'][$theField]['config']['uploadfolder']; } if ($uploadPath !== '') { $theDestFile = $this->fileFunc->getUniqueName($this->fileFunc->cleanFileName($infoArr['name']), PATH_site . $uploadPath); GeneralUtility::upload_copy_move($infoArr['tmp_name'], $theDestFile); // Setting the filename in the list $fI2 = pathinfo($theDestFile); $fileNameList[] = $fI2['basename']; $this->filesStoredInUploadFolders[] = $theDestFile; } } // Implode the list of filenames $this->dataArr[$theField] = implode(',', $fileNameList); } }