简体   繁体   English

如何使用typo3/extbase 触发下载?

[英]How can I trigger a download with typo3/extbase?

I'm using Typo3 with extbase and fluid.我正在使用带有 extbase 和流体的 Typo3。 I have a Controller with an action called downloadAction() .我有一个控制器,有一个名为downloadAction()的动作。 After calling the action the system tries to render the download-template (but I just want to start a download).调用该操作后,系统会尝试呈现下载模板(但我只想开始下载)。

public function downloadAction($id) {
  // create file
  // send header
  // dump file
  // exit
}

How can I dump the created download-File and send a download header instead of the normal render process?如何转储创建的download-File并发送下载标头而不是正常的渲染过程? What is the best way?什么是最好的方法?

Thanks谢谢

I did this in a project some months ago, it's pretty straight forward.几个月前我在一个项目中做了这个,它非常简单。

    /**
     * @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 '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;

                case 'exe':                 
                default:
                    $cType = 'application/octet-stream';
                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;   
    }

You can define a special PageType for download requests:您可以为下载请求定义一个特殊的 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" must be replaced by your extension's name. “efempty”必须替换为您的扩展名。

You are now able to trigger the download like this:您现在可以像这样触发下载:

<f:link.action pageType="1249058993" action="download" controller="ControllerName">Download</f:link.action>

Update : This actually doesn't work with activated compression because the Content-Length will still represent the uncompressed size.更新:这实际上不适用于激活的压缩,因为 Content-Length 仍将表示未压缩的大小。 eID could be used as workaround in fact there is even a official call for that: eID 可以用作解决方法,实际上甚至有官方呼吁:

eID = "dumpFile" see typo3/sysext/core/Resource/PHP/FileDumpEID.php eID = "dumpFile" 见typo3/sysext/core/Resource/PHP/FileDumpEID.php

However this call won't force a download but instead "dump" it.但是,此调用不会强制下载,而是“转储”它。 I've made a ticket @ Forge to fix this (which was accepted and is targeted for LTS 7): https://forge.typo3.org/issues/67111我已经在@ Forge 上发了一张票来解决这个问题(已被接受并针对 LTS 7): https : //forge.typo3.org/issues/67111

Old answer : As for now the easiest way to accomplish this is:旧答案:至于现在最简单的方法是:

TypoScript Constants 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 Setup打字稿设置

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

Controller Action控制器动作

/**
 * 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'
    );
}

Fluid体液

<f:link.action controller="ControllerName" pluginName="PluginName" action="download" arguments="{model: '{model.uid}'}" format="download" title="{model.file.originalResource.title}">Download</f:link.action>

The benefits vs the other mentioned answers are as following:与其他提到的答案相比,好处如下:

  • Proper headers (including mime/type)正确的标题(包括 mime/type)
  • Extbase formats instead typenum Extbase 格式代替 typenum

Side note: iPhone ignores the Content-Disposition headers (always inline)旁注:iPhone 忽略 Content-Disposition 标头(始终内联)

About the "exit" concerns i've not tested it but with the page type it might work if you would use a own PHPView (StandaloneView?).关于“退出”问题,我还没有测试过,但是如果您使用自己的 PHPView(StandaloneView?),它可能会使用页面类型。

How can I dump the created download-File and send a download header instead of the normal render process?如何转储创建的下载文件并发送下载标头而不是正常的渲染过程?

As long as headers haven't already been sent , there is nothing at all stopping you from emitting your headers, sending the content and actually calling exit , though you might want to check for output buffering and clear any open buffers before doing so.只要尚未发送标头,就没有什么可以阻止您发出标头、发送内容并实际调用exit ,尽管您可能希望在执行此操作之前检查输出缓冲清除所有打开的缓冲区 You might also want to inspect the list of headers that will be sent .您可能还想检查将发送的标头列表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM