【问题标题】:Trigger download dialog right after headers received收到标头后立即触发下载对话框
【发布时间】:2018-05-07 08:35:49
【问题描述】:

我有一个 PDF 导出文件,需要一段时间才能创建 PDF。我希望用户能够单击导出链接并立即显示下载对话框。这样他们就可以开始下载并等待它完成。不要点击链接,而是等待生成,然后再次等待下载。

这是一个非常简单的 PHP 示例:

<?php

header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename=test.pdf');
flush();

// time consuming PDF creation happens here
sleep(15);
echo 'pdf contents would be here';

想法是发送适当的标题,将它们flush()到浏览器,慢慢创建PDF,最后发送到浏览器。

这在 chrome 中完美运行。下载对话框立即弹出,睡眠是下载等待时间的一部分。

在 Firefox 和 InternetExplorer 中,这不起作用。这些浏览器会等待整整 15 秒,然后才会显示下载对话框。

任何想法如何使下载对话框立即弹出将不胜感激。

【问题讨论】:

    标签: php http internet-explorer firefox download


    【解决方案1】:

    某些浏览器会在显示下载对话框之前等待实际内容。 因此,解决方案很简单:在创建 PDF 内容之前发送一些 PDF 内容。

    等一下。 有东西之前怎么寄? 这听起来像是需要一台时光机,对吧? 别担心,有办法绕过它。

    PDF content starts with %PDF,因此您只需在调用 flush() 之前发送%PDF。 PDF 创建完成后,在回显之前删除新创建的 PDF 内容的前 4 个字节。

    <?php
    // disable output buffering
    while (@ob_end_clean());
    
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename=test.pdf');
    
    // send some content to trigger the download dialog
    echo '%PDF';
    flush();
    
    // time consuming PDF creation happens here
    sleep(15);
    $pdfContent = '%PDF-pdf contents would be here';
    echo substr($pdfContent, 4);
    

    此解决方案适用于任何语言,因为它不依赖于任何仅 PHP 的功能。

    如果你想做绝对最小值,你也可以发送 1 个字节 %,然后在回显之前只删除第一个字节。 结果一样。

    【讨论】:

    • 这也是我的猜测。我已经尝试过了,但它不起作用。可以肯定的是,我再次在 Firefox 中尝试了您的代码。在弹出下载对话框之前它仍然等待 15 秒。
    • @AndreasGohr 我假设您只使用flush(),因为您已经禁用了输出缓冲。它不起作用的事实意味着你没有。无论输出缓冲配置如何,我都更新了代码以使其正常工作。
    • 很奇怪。你是对的,我以为我没有启用输出缓冲,但你的添加它确实有效!非常感谢!
    【解决方案2】:

    这是一个普遍问题,与任何特定语言无关。 我们正在制定一个流程,等待一段时间,直到生成 PDF,然后开始我们的下载流程。

    因此,为了等待 PDF 生成,我们将使用 sleep() 函数来允许进程等待指定的时间段 - 如上所述的 15。

    sleep(15)
    

    现在我们不能flush()在将pdf生成到浏览器之前的空内容。所以我们可以在 head 之前发送一些静态内容并开始我们的刷新过程。

    在成功生成 PDF 后,我们可以删除之前添加的内容,并将更新后的内容回显到浏览器的 flush() 函数中。

    所以整体代码是,

    <?php
    
    // Initialize the Basic Header
    
    ob_start(); // Start Buffering
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename=test.pdf');
    
    // Adding content before the PDF Generation Process
    echo 'demo';
    
    // Flushing content to the Browser
    
    ob_end_flush();
    ob_flush(); 
    flush();
    
    // time consuming PDF creation happens here
    sleep(15);
    
    $Content = 'demoother pdf content';
    
    // Removind the Added Content
    echo substr($Content, 4);
    
    ?>
    

    【讨论】:

    • "所以为了等待 PDF 生成,我们将使用 sleep() 函数"。这不是问题中sleep() 的目的。差远了。你应该再读一遍问题,如果你仍然不明白,请询问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    相关资源
    最近更新 更多