1

所以首先我想告诉我,我在使用标头和使用输出缓冲区方面是个新手。所以我正在为 liferay 开发 php portlet,我在文件下载方面遇到了一些问题。我试图简单地使用'a href'来做到这一点,但问题是通过php上传的文件在刷新apache之前不可用,所以我尝试了另一种使用header()函数的方法。

所以我会试着解释我的问题。当我在简单的 php 项目上尝试以下代码时,它工作正常:

    <?php

$path = "/mysecretdir/upload/"; // change the path to fit your websites document structure
$fullPath = $path.$_GET['download_file'];

if ($fd = fopen ($fullPath, "r")) {

    $fsize = filesize($fullPath);

    $path_parts = pathinfo($fullPath);
    $ext = strtolower($path_parts["extension"]);

    switch($ext) {

        case "pdf":
            $ctype = "application/pdf";
            break;
        case "exe":
            $ctype = "application/octet-stream";
            break;
        case "zip":
            $ctype = "application/zip";
            break;
        case "doc":
            $ctype = "application/msword";
            break;
        case "xls":
            $ctype = "application/vnd.ms-excel";
            break;
        case "ppt":
            $ctype = "application/vnd.ms-powerpoint";
            break;
        case "gif":
            $ctype = "image/gif";
            break;
        case "png":
            $ctype = "image/png";
            break;
        case "jpeg":
            $ctype = "image/jpg";
            break;
        case "jpg":
            $ctype = "image/jpg";
            break;
        case "mp3":
            $ctype = "audio/mp3";
            break;
        case "wav":
            $ctype = "audio/x-wav";
            break;
        case "wma":
            $ctype = "audio/x-wav";
            break;
        case "mpeg":
            $ctype = "video/mpeg";
            break;
        case "mpg":
            $ctype = "video/mpeg";
            break;
        case "mpe":
            $ctype = "video/mpeg";
            break;
        case "mov":
            $ctype = "video/quicktime";
            break;
        case "avi":
            $ctype = "video/x-msvideo";
            break;
        case "src":
            $ctype = "plain/text";
            break;
        default:
            $ctype = "application/force-download";
    }

    header("Pragma: public");

    header("Expires: 0");

    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");

    header("Cache-Control: private",false);

    header("Content-type: " . $ctype);

    header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");

    header("Content-Transfer-Encoding: binary");

    //header("Content-length: $fsize");
    header("Cache-control: public"); //use this to open files directly    

    while(!feof($fd)) {
        echo fread($fd, 4096); 
    flush();
    }
}
fclose ($fd);
?>

从 index.php 我用 href="download.php?download_file=/something/" 调用它

好的,但现在重点。当我在liferay portlet 中使用它时,文件很奇怪。它将整个生成的 HTML 文件放入创建的文件中。所以它坏了。我不知道为什么。我不知道标头是否从其他地方发送了一些信息,也不知道如何修复它。

我花了几个小时寻找一些解决方案,但不知道如何以某种方式为标题创建“会话”,因为我认为它们有问题。因为没有回声,它只打印文件和其他项目的内容 - 更简单的 php 应用程序不是它的门户的一部分!但也许我错了。

那么请有人可以帮助我吗?有什么建议吗?

4

2 回答 2

1

我无法帮助您解决特定的 php-portlet 问题(我从未将 Liferay 与 php 一起使用),但听起来您获得了“围绕”您下载的文件生成的整个页面 HTML。这就是您在仅呈现 portlet 时得到的结果:portlet 始终嵌入在 HTML 页面中,因此您不能在 HTTP 级别上提供特定的标头以及 portlet 的标准呈现输出。

您需要serveResource的是 portlet 的生命周期阶段。这将允许您提供不属于页面的内容,但您可以完全控制下载和 HTTP 标头。如何使用 php portlets 做到这一点,我将不得不留给你。

编辑(附加信息):正如您在评论中所问的那样,我发现了一篇较旧的(可能需要修改)Wiki 文章,其中讨论了使用 state=exclusive 来执行相同的技巧 - 而不是我上面建议的 serveResource。我不知道这是由于文章年代久远还是因为 PHP portlet 不支持该生命周期,但您可能会在相关文章和链接文章中找到一些内容。注意:如果我没记错的话,serveResource 会生成一个 p_p_lifecycle=2 参数,而本示例使用 p_p_lifecycle=0(渲染)和 p_p_state=exclusive。试试这是否符合您的要求

但是,请考虑 Marc B 关于您的代码不安全且过于硬编码的评论。对于根本问题有更好的解决方案——例如,Liferay 提供了文档库来开箱即用地上传/下载文件。而且不存在这些问题。

于 2012-09-17T14:33:05.420 回答
0

如果您以空格或任何其他字符开始您的 PHP 文件,标题将不起作用并且显示/下载将失败。<?php确保标签之前没有任何内容。

除此之外,这应该可以工作(如果您在浏览器中没有收到错误)。

另一方面,如果您看到实际的 PHP 代码,您的服务器不支持 PHP。

于 2012-09-17T14:22:10.017 回答