Silverstripe 3.2:如何使用按钮强制从 CMS 下载文件?

Silverstripe 3.2: How to force a download of a file from the CMS with a button?

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

Failed to load resource: the server responded with a status of 500 (Warning at line 257 of /Applications/MAMP/htdocs/myproject/framework/control/HTTPResponse.php)

[Recoverable Error] Object of class SS_HTTPResponse could not be converted to string.

所以我假设行

return SS_HTTPRequest::send_file($filedata, $fileName, 'application/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');

}

您打算将字符串传递给 send_file 函数,而不是传递 "File" 对象。

我会更改行

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

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

但是,最好写成检查 File::find(...) returns 一个文件而不是 null!

File::find() returns 如果文件存在则为 File 对象,否则为 null。它从不 returns 二进制数据,这就是 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');
}

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

我让文件在新选项卡中打开,这样用户就可以自己下载或者直接在浏览器中查看 window:

首先我没有使用 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()
        );
    }

}

我们可以使用 LiteralField 来创建一个 link 文件。通过将 link 的 class 设置为 ss-ui-button 我们可以使 link 看起来像一个按钮。

这里是一个示例 link 特定文件:

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

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

这里是一个例子 link 通过 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;
}