Как я могу запустить загрузку с typo3/extbase?
Я использую Typo3 с extbase и жидкости. У меня есть контроллер с действием называется downloadAction()
, После вызова действия система пытается отобразить шаблон загрузки (но я просто хочу начать загрузку).
public function downloadAction($id) {
// create file
// send header
// dump file
// exit
}
Как я могу сбросить созданное download-File
и отправить заголовок загрузки вместо обычного процесса рендеринга? Какой самый лучший способ?
Спасибо
4 ответа
Я сделал это в проекте несколько месяцев назад, это довольно просто.
/**
* @param string $fileName
* @return void
*/
public function downloadAction($fileName) {
$file = $this->settings['uploadFolder'] . 'uploadedPhotos/' . $fileName;
if(is_file($file)) {
$fileLen = filesize($file);
$ext = strtolower(substr(strrchr($fileName, '.'), 1));
switch($ext) {
case 'txt':
$cType = 'text/plain';
break;
case 'pdf':
$cType = 'application/pdf';
break;
case 'exe':
$cType = 'application/octet-stream';
break;
case 'zip':
$cType = 'application/zip';
break;
case 'doc':
$cType = 'application/msword';
break;
case 'xls':
$cType = 'application/vnd.ms-excel';
break;
case 'ppt':
$cType = 'application/vnd.ms-powerpoint';
break;
case 'gif':
$cType = 'image/gif';
break;
case 'png':
$cType = 'image/png';
break;
case 'jpeg':
case 'jpg':
$cType = 'image/jpg';
break;
case 'mp3':
$cType = 'audio/mpeg';
break;
case 'wav':
$cType = 'audio/x-wav';
break;
case 'mpeg':
case 'mpg':
case 'mpe':
$cType = 'video/mpeg';
break;
case 'mov':
$cType = 'video/quicktime';
break;
case 'avi':
$cType = 'video/x-msvideo';
break;
//forbidden filetypes
case 'inc':
case 'conf':
case 'sql':
case 'cgi':
case 'htaccess':
case 'php':
case 'php3':
case 'php4':
case 'php5':
exit;
default:
$cType = 'application/force-download';
break;
}
$headers = array(
'Pragma' => 'public',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Description' => 'File Transfer',
'Content-Type' => $cType,
'Content-Disposition' => 'attachment; filename="'. $fileName .'"',
'Content-Transfer-Encoding' => 'binary',
'Content-Length' => $fileLen
);
foreach($headers as $header => $data)
$this->response->setHeader($header, $data);
$this->response->sendHeaders();
@readfile($file);
}
exit;
}
Вы можете определить специальный PageType для запросов на скачивание:
download = PAGE
download {
typeNum = 1249058993
10 < tt_content.list.20.efempty_pi1
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
additionalHeaders = Content-type:application/octet-stream
}
}
}
"efempty" должно быть заменено именем вашего добавочного номера.
Теперь вы можете запустить загрузку следующим образом:
<f:link.action pageType="1249058993" action="download" controller="ControllerName">Download</f:link.action>
Обновление: это на самом деле не работает с активированным сжатием, потому что Content-Length по-прежнему будет представлять несжатый размер. В качестве обходного пути можно использовать eID, для этого даже существует официальный призыв:
eID = "dumpFile", см. typo3/sysext/core/Resource/PHP/FileDumpEID.php
Однако этот вызов не заставит загрузку, а вместо этого "сбросит" ее. Я сделал запрос @ Forge, чтобы это исправить (что было принято и предназначено для LTS 7): https://forge.typo3.org/issues/67111
Старый ответ: На данный момент самый простой способ сделать это:
Константы TypoScript
# ASCII "download" in Numbers (4-15-23-14-12-15-1-4) - See http://rumkin.com/tools/cipher/numbers.php
plugin.tx_extensionname.view.formatToPageTypeMapping.download = 4152314121514
Настройка TypoScript
tx_extensionname_download = PAGE
tx_extensionname_download {
typeNum < plugin.tx_extensionname.view.formatToPageTypeMapping.download
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
debug = 0
no_cache = 1
}
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = ExtensionName
pluginName = PluginName
vendorName = VENDOR
controller = ControllerName
action = download
view < plugin.tx_extensionname.view
persistence < plugin.tx_extensionname.persistence
settings < plugin.tx_extensionname.settings
}
}
Действие контроллера
/**
* Download
*
* @param \VENDOR\ExtensionName\Domain\Model\Model $model
* @return void
* @ignorevalidation $model
*/
public function downloadAction($model) {
if ($model->getFile()) {
$model->getFile()->getOriginalResource()->getOriginalFile()->getStorage()->dumpFileContents(
$model->getFile()->getOriginalResource(),
$asDownload = TRUE,
$alternativeFilename = $model->getFile()->getOriginalResource()->getName()
);
exit;
}
$this->throwStatus(
$statusCode = 404,
$statusMessage = 'Not Found'
);
}
жидкость
<f:link.action controller="ControllerName" pluginName="PluginName" action="download" arguments="{model: '{model.uid}'}" format="download" title="{model.file.originalResource.title}">Download</f:link.action>
Преимущества против других упомянутых ответов следующие:
- Правильные заголовки (включая mime / type)
- Extbase форматирует вместо typenum
Примечание: iPhone игнорирует заголовки Content-Disposition (всегда встроенные)
О проблемах "выхода" я не проверял, но с типом страницы он мог бы работать, если бы вы использовали собственный PHPView (StandaloneView?).
Как я могу сбросить созданный файл загрузки и отправить заголовок загрузки вместо обычного процесса рендеринга?
Пока заголовки еще не отправлены, ничто не мешает вам отправлять заголовки, отправлять контент и фактически вызывать exit
, хотя вы можете захотеть проверить выходную буферизацию и очистить все открытые буферы перед этим. Вы также можете проверить список заголовков, которые будут отправлены.