【问题标题】:Creating a download link for .jpg file using PHP使用 PHP 为 .jpg 文件创建下载链接
【发布时间】:2009-10-13 19:47:11
【问题描述】:

我认为这应该很容易。我有一个分页的图片库,每张图片下面都有一个小链接,上面写着“下载 Comp”。这应该允许人们快速将 .jpg 文件(带有 PHP 生成的水印)下载到他们的计算机上。

现在,我知道我可以直接链接到 .jpg 文件,但这需要用户在新窗口中打开图像、右键单击、另存为...等。相反,我想要“下载 Comp" 链接以立即开始下载文件。

PHP.net 似乎建议使用 readfile(),因此每个“Download Comp”链接都被回显为“?download=true&g={$gallery}&i={$image}”。

然后在页面顶部,我查看是否 $_GET['download'] var isset,如果是,我运行以下代码:

if(isset($_GET['download'])) {
$gallery = $_GET['g'];
$image = $_GET['i'];
$file = "../watermark.php?src={$gallery}/images/{$image}";
header('Content-Description: File Transfer');
    header('Content-Type: application/jpeg');
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: public');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
readfile($file);

}

链接需要很长时间,然后它会弹出一个对话框提示,要求您打开或保存文件,但是一旦您保存并尝试打开它,它就会说文件已损坏并且无法打开。

有什么想法吗?

【问题讨论】:

  • 你打开fopen_wrappers了吗?否则,readfile 不能接受 URL 参数。
  • @Ken:很好,我什至没有注意到它是 URL 而不是路径。
  • readfile() 只会尝试下载绝对 URL。它需要以 http://hostname.... 开头。更好的是,不要使用 URL。请参阅下面的答案。

标签: php file download hyperlink


【解决方案1】:

不要将 $file 设置为相对 url。 readfile 函数将尝试访问服务器上的 php 文件。那不是你想要的。在您的情况下,watermark.php 文件似乎会发送您想要的内容,因此您可能只需设置它需要的环境并包含它。

<?php
if(isset($_GET['download'])) {
    $gallery = $_GET['g'];
    $image = $_GET['i'];
    $_GET['src'] = "{$gallery}/images/{$image}";

    header('Content-Description: File Transfer');
    header('Content-Type: image/jpeg');
    header('Content-Disposition: attachment; filename='.basename($image));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: public');
    header('Pragma: public');
    ob_clean();
    include('../watermark.php');
    exit;
}

另一种(更简单)的方法是修改 watermark.php。添加查询参数以使其发送正确的标头以强制下载并链接到该标头

<a href="watermark.php?src=filename.jpg&download=true)">...</a>

水印.php:

<?php
if (isset($_GET['download']) && $_GET['download'] == 'true') {
    header('Content-Description: File Transfer');
    header('Content-Type: image/jpeg');
    header('Content-Disposition: attachment; filename='.basename($src));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: public');
    header('Pragma: public');
}
// continue with the rest of the file as-is

另外,您不需要调用flush()。此时不应有任何输出要发送,因此没有必要。

【讨论】:

  • mcrumley - 谢谢。现在我选择你的第一个选项只是为了让它工作,现在文件下载速度更快。但是,该文件仍然无法打开。预览显示“无法打开文件。它可能已损坏或预览无法识别的文件格式。”有什么想法吗?页面在这里:homewoodphoto.jhu.edu//gallery/20030101_test_gallery
  • 我试过的文件是空的。包含文件路径是否正确?您是否在错误日志中收到任何错误?
【解决方案2】:
header('Content-Type: image/jpeg');

也许?

【讨论】:

  • 我认为 Content-Type 标头只是告诉浏览器如何处理它。如果存在二进制数据,则无论 MIME 类型如何,它都应该可以正常工作。
【解决方案3】:

我认为您可能需要在调用readfile() 之后调用exit(),以确保没有其他内容被写入输出缓冲区。

【讨论】:

    【解决方案4】:

    这似乎是一个安全问题。

    如果有人进入怎么办:

    $g = '../../../../../../';
    $i = '../../sensitive file at root';
    

    如何让 .htaccess(如果您使用 apache)i 为画廊目录提供 jpeg 作为下载而不是正常。

    【讨论】:

      【解决方案5】:

      另外,试试file_get_contents() 而不是readfile()。我发现它在更多情况下有效。我还建议您在输出图像数据后使用ob_flush()。我从来不需要使用ob_clean()flush() 来让这种事情发挥作用。

      正如 Eric 所说,如果您仍然无法正常工作,您可能还想在那里拨打exit() 的电话,以防万一您在最后遇到一些垃圾数据。

      【讨论】:

      • ob_clean() 将擦除缓冲区。需要在镜像写入之前调用,否则数据会被清除。
      • 我的错。我在想ob_flush()。更改答案以反映这一点。
      猜你喜欢
      • 2016-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 2015-07-01
      • 2020-06-27
      相关资源
      最近更新 更多