【问题标题】:Silverstripe 3.2: How to force a download of a file from the CMS with a button?Silverstripe 3.2:如何通过按钮强制从 CMS 下载文件?
【发布时间】:2016-01-18 11:11:58
【问题描述】:

我在通过单击 CMS 中的按钮下载 pdf 文件时遇到问题。我正在使用模块BetterButtons。按钮本身工作正常,但下载文件时出错。我总是收到这个错误:

加载资源失败:服务器响应状态为 500 (第 257 行的警告 /Applications/MAMP/htdocs/myproject/framework/control/HTTPResponse.php)

[可恢复的错误] SS_HTTPResponse 类的对象不能被 转换成字符串。

所以我假设这条线

返回 SS_HTTPRequest::send_file($filedata, $fileName, '应用程序/pdf');

$filedata 有问题或有问题... 正确的方法是什么?

我的代码:

在我有下载按钮的数据对象中:

private static $better_buttons_actions = array (
            'printFilesPDF'
);

public function getBetterButtonsActions() {
        $fields = parent::getBetterButtonsActions();
        $fields->push(BetterButtonCustomAction::create('printFilesPDF', 'Print files'));
        return $fields;
}

public function printFilesPDF() {

        $filedata = File::find("assets/PDF/myFile.pdf");
        $fileName = "myFile.pdf";
        return SS_HTTPRequest::send_file($filedata, $fileName, 'application/pdf');

}

【问题讨论】:

  • 每当您收到“500 错误”返回时,您需要更改为开发模式,这会给您一个错误,可能会帮助您解决或这里的其他人帮助您解决
  • 嗨。谢谢你这么快回答。我处于开发模式..单击按钮后重新加载页面后发现“真实”错误:[Recoverable Error] SS_HTTPResponse 类的对象无法转换为字符串。不幸的是仍然不知道该怎么做:( ...你能帮我吗?
  • @iraira 我遇到了同样的问题。你找到解决方案了吗?
  • @csy_dot_io 是的,我找到了解决方案。待我在家时,我会将其作为答案发布。
  • 那将是完美的。非常感谢!

标签: download httprequest httpresponse silverstripe


【解决方案1】:

我找到了解决办法。它不是最好的,但它对我有用。

我让文件在新标签页中打开,这样用户就可以自己下载或在浏览器窗口中查看:

首先我没有使用BetterButtonCustomAction,而是使用BetterButtonLink

public function getBetterButtonsActions() {
    $fields = parent::getBetterButtonsActions();
    $fields->push(new BetterButtonLink('Download the file', "assets/myfile.pdf"));
}

通过使用BetterButtonLink,我遇到了以下问题: 每次我单击该按钮时,它都会尝试通过 AJAX 请求在 CMS 管理员中打开 PDF,这会导致显示编码文本。您可以在这里找到一个简单的解决方案:https://github.com/unclecheese/silverstripe-gridfield-betterbuttons/issues/64

所以我的最终代码是

public function getBetterButtonsActions() {
    $fields = parent::getBetterButtonsActions();
    $fields->push(new BetterButtonLink_NewWindow('Download the file', "assets/myfile.pdf"));
}

还有BetterButtonLink_NewWindow 代码:

class BetterButtonLink_NewWindow extends BetterButtonLink {

    /**
     * Gets the HTML representing the button
     * @return string
     */
    public function getButtonHTML() {
        return sprintf(
            '<a class="ss-ui-button %s" href="%s" target="_blank">%s</a>',
            $this->extraClass(),
            $this->getButtonLink(),
            $this->getButtonText()
        );
    }

}

【讨论】:

    【解决方案2】:

    您打算将字符串传递给 send_file 函数,而不是传递“文件”对象。

    我会换行

     $filedata = File::find("assets/PDF/myFile.pdf");
    

    $filedata = file_get_contents(File::find("assets/PDF/myFile.pdf")->getFullPath());
    

    但是,最好这样写来检查 File::find(...) 返回一个文件而不是 null!

    【讨论】:

    • 我尝试了您的解决方案,但仍然遇到相同的错误:“SS_HTTPResponse 类的对象无法转换为字符串”
    • 你能不能先用return SS_HTTPRequest::send_file("test", "test.html", 'text/html'); 这样的简单返回来测试。只是为了确定错误在哪里。 Barrys 提示应该可以工作,但您仍然会收到看起来很奇怪的错误。您使用的 SS 版本是什么?
    • 所以我的评论是更正发送到 HTTP 请求中的数据。我也不确定你是如何使用请求的,因为你似乎将它添加到一个动作中......通常我会在控制器上最后一次返回动作函数......你可以尝试这样做吗?一个简单的控制器,将其作为其操作之一输出,而不需要更好的按钮。
    • 嗯...经过几次测试,我发现当您从前端触发代码/函数时(例如,当我单击模板中的按钮时),代码/函数可以完美运行,但不要当我从 CMS 触发此功能时工作(通过 betterbuttons 操作)...你知道可能是什么原因吗?
    【解决方案3】:

    File::find() 如果文件存在则返回一个 File 对象,如果不存在则返回 null。它从不返回二进制数据,这就是 HTTPResponse 不会将其转换为字符串的原因。

    如果 file_get_contents 不起作用,请检查它是否在您的计算机上被禁用。

    //attempt to find the file
    $file = File::find("path/to/my/file.txt");
    
    //you need to check that the file is File and not null
    if($file && $file instanceof File) {
        //get the file path
        $path = $file->getFullPath();
    
        //get the file data. If file_get_contents() doesn't work, you might need fopen() or file() instead
        $fileData = file_get_contents($path);
        $fileName = "myFile.pdf";
        return SS_HTTPRequest::send_file($fileData, $fileName, 'application/pdf');
    }
    

    【讨论】:

    • 好吧..我做了一些测试,发现你的代码在前端运行良好(例如,当我点击模板中的按钮时),但是当我触发这个函数时我仍然得到同样的错误来自 CMS... 你知道可能是什么原因吗?
    【解决方案4】:

    我们可以使用LiteralField 来创建指向文件的链接。通过将链接的类设置为ss-ui-button,我们可以使链接看起来像一个按钮。

    这是一个指向特定文件的示例链接:

    LiteralField::create(
        'DownloadLink',
        '<a href="assets/myfile.pdf" target="_blank" class="ss-ui-button" download>Download the file</a>'
    );
    

    这可用于getCMSFieldsgetCMSActions 以使按钮显示在字段区域或按钮区域中。

    这是一个通过getCMSFields 指向$has_one 控制文件的示例链接:

    public function getCMSFields() {
        $fields = parent::getCMSFields();
        if ($this->File()->exists()) {
            $fields->addFieldToTab('Root.Main', 
                LiteralField::create(
                    'DownloadLink',
                    '<a href="' . $this->File()->Link() . '" target="_blank" class="ss-ui-button" download>Download the file</a>'
                )
            );
        }
        return $fields;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多