【问题标题】:cURL using PHP: download file to client results in minorly corrupt filecURL 使用 PHP:将文件下载到客户端会导致文件轻微损坏
【发布时间】:2014-11-03 20:11:38
【问题描述】:

使用我将在下面发布的脚本,我使用 PHP 中的 cURL 成功地将 JPG、PNG 或 PPT(x) 文件从服务器下载到客户端。但是,当我打开以这种方式保存的任何 PowerPoint 文件时,我收到错误消息“PowerPoint 发现 FILENAME.pptx 中的内容存在问题。Powerpoint 可以尝试修复演示文稿。如果您信任此演示文稿的来源,请单击修复。”

function download_file( $linkRequested = '', $whichFileToDownload = '' )
{
    // literal dam reference. We dont want wider access to our files. 
    $fileWithPath = $_SERVER['HTTP_HOST'] . '/files/xxxXXX/specific/' . $whichFileToDownload;

    /***   define the file type for the download MT ***/
    // set generic mime type, in case we don't match 
    $mimeType = 'application/octet-stream';
    // JPG
    if ( preg_match('|\.jpg$|i', $whichFileToDownload) ) {
        $mimeType = 'IMAGETYPE_JPEG';
    }
    // PNG
    if ( preg_match('|\.png$|i', $whichFileToDownload) ) {
        $mimeType = 'IMAGETYPE_PNG';
    }
    // older PowerPoint 
    if ( preg_match('|\.ppt$|i', $whichFileToDownload) ) {
        $mimeType = 'application/vnd.ms-powerpoint';
    }
    // PowerPoint 
    if ( preg_match('|\.pptx$|i', $whichFileToDownload) ) {
        $mimeType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
    }

    /***  do curl MT ***/
    $ch = curl_init($fileWithPath);
    curl_setopt( $ch, CURLOPT_URL, $fileWithPath );

    $fp = fopen($fileWithPath, 'wb');

    // set the curl options. Order is important. 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt($ch, CURLOPT_FILE, $fp);

    // get the contents of the file as text 
    $content = curl_exec($ch);

    // describe the file header for the client 
    header('Content-Description: File Transfer');
    // set mime type for download of binary data 
    header('Content-Type: ' . $mimeType);
    // Attachment indicates save the file. Filename sets file name
    header('Content-Disposition: attachment; filename="' . $whichFileToDownload . '"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . strlen($content));

    // send the file 
    ob_clean();
    flush();
    echo $content;

    // clean up loose ends 
    flush();
    curl_close($ch);
    fclose($fp);

    // don't return anything 
}

我没有正确关闭流吗?我不知道问题是什么。

注意:JPG 和 PNG 文件可以正常打开。 & 点击“修复”成功打开文件。

【问题讨论】:

  • 我会说,在一种情况下,您的内容配置有错误,因为它需要 filename="'. $whichFileToDownload"',但您缺少围绕该值的 "" 封装。我找不到其他东西了
  • 看起来您正试图从运行脚本的同一台服务器下载文件...使用readfile($filename) 流式传输文件,而不是通过 cURL 将其加载到变量中。此外,您的正则表达式将匹配的不仅仅是文件扩展名。它们应该像/\.jpg$/i(字面句号,只匹配字符串末尾)
  • 比较文件的前后版本,例如将两者都加载到十六进制编辑器或二进制差异中。您可能会在文件的开头或结尾找到一些 PHP 错误/警告或其他“绒毛” - 可能是结尾。
  • 我已经在此处和我的脚本中包含了您的错误修复。现在我开始阅读有关 readfile() 的信息。谢谢!

标签: php curl


【解决方案1】:

从脚本中准确管理文件下载并不是一个好主意。由于您的文件在您的网络服务器上,因此最好使用更强大的方法,例如:x_sendfile mod for apache:

https://tn123.org/mod_xsendfile/ref

用法:

    header("X-Sendfile: $path_to_somefile");
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"$somefile\"");
    exit;

此外,您的脚本放弃了暂停和恢复下载的可能性(您应该手动管理 RangeContent-Range 标头,这很容易出错)。

【讨论】:

  • 有趣。我以前从未听说过。以下是对 x_sendfile 是什么/它如何为感兴趣的人工作的更好解释:yiiframework.com/wiki/129/…
  • (我使用的是 IIS,所以 apache mods 无济于事。)但是,我想我应该包括一些我的动机。用于下载的 JPG 和 PNG 文件被 IE8+ 强制查看,因为它不符合“下载”href 属性的规范。所以我构建了这个工具来为所有浏览器下载,因为过滤代理不太可靠。但是我刚刚意识到 PPT 不受 IE8+ 的强制查看功能的影响,所以我可以通过只在图像上使用这个脚本来规避我的问题。谢谢,你可能没有直接帮助我,但这有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-29
  • 1970-01-01
  • 2013-07-12
  • 2013-01-30
  • 2012-04-09
  • 1970-01-01
相关资源
最近更新 更多