php使用header()强制下载已下载的文件

php使用header()强制下载已下载的文件,php,header,download,buffer,liferay,Php,Header,Download,Buffer,Liferay,因此,首先我想告诉大家,我对头的使用和输出缓冲区的使用非常熟悉。因此,我正在为liferay开发PHPPortlet,我在文件下载方面遇到了一些问题。我试着简单地用“a href”来实现,但问题是,在刷新apache之前,通过php上传的文件不可用,所以我用header()函数尝试了另一种方法 所以我会尽力解释我的问题。当我在简单php项目上尝试以下代码时,效果很好: <?php $path = "/mysecretdir/upload/"; // change the path

因此,首先我想告诉大家,我对头的使用和输出缓冲区的使用非常熟悉。因此,我正在为liferay开发PHPPortlet,我在文件下载方面遇到了一些问题。我试着简单地用“a href”来实现,但问题是,在刷新apache之前,通过php上传的文件不可用,所以我用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文件放入创建的文件中。所以它坏了。我不知道为什么。我不知道标题是否从其他地方发送了一些信息,也不知道如何修复它

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


有人能帮帮我吗?有什么建议吗?

如果您的PHP文件以空格或任何其他字符开头,则标题将不起作用,显示/下载将失败。确保在
之前没有任何内容。如果用空格或任何其他字符启动PHP文件,则标题将不起作用,显示/下载将失败。请确保在下载文件之前没有任何内容,我无法帮助您解决特定的php portlet问题(我从未将Liferay与php一起使用),但听起来好像您在下载的文件周围生成了整个页面的HTML。这就是您在呈现portlet时得到的结果:portlet总是嵌入在HTML页面中,因此您不能在HTTP级别上为portlet的标准呈现输出提供特定的头

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

编辑(其他信息):正如您在评论中询问的那样,我发现了一个更老的(可能需要修改)方法,它谈到使用state=exclusive来完成相同的任务,而不是我上面建议的服务器资源。我不知道这是由于文章的年代,还是因为PHP Portlet不支持该生命周期,但是您可能会在那里以及相关的链接文章中找到一些东西。注意:如果我没有弄错的话,ServerSource将生成一个p_p_lifecycle=2参数,而本例使用p_p_lifecycle=0(渲染)和p_p_state=exclusive。试试看这是否符合你的要求


但是请考虑Marc B关于你的代码不安全和过于硬编码的评论。对于潜在问题有更好的解决方案-例如,Liferay提供了文档库,可以随时更新/下载文件。这并不存在这些问题。

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

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

编辑(其他信息):正如您在评论中询问的那样,我发现了一个更老的(可能需要修改)方法,它谈到使用state=exclusive来完成相同的任务,而不是我上面建议的服务器资源。我不知道这是由于文章的年代,还是因为PHP Portlet不支持该生命周期,但是您可能会在那里以及相关的链接文章中找到一些东西。注意:如果我没有弄错的话,ServerSource将生成一个p_p_lifecycle=2参数,而本例使用p_p_lifecycle=0(渲染)和p_p_state=exclusive。试试看这是否符合你的要求


但是请考虑Marc B关于你的代码不安全和过于硬编码的评论。对于潜在问题有更好的解决方案-例如,Liferay提供了文档库,可以随时更新/下载文件。这并不存在这些问题。

您的代码允许恶意用户下载服务器上的任何文件。考虑<代码>下载。php?同样,整个fopen()/fread业务也是毫无意义的。只需使用
readfile()
。加上。。。为什么要硬编码mime类型?它允许你处理服务器知道的任何mimetype。我只是在搜索一些解决方案,这是我找到并尝试使用的解决方案。那么,我该如何链接它呢?而且它还不能解决我的输出问题:(你的代码允许恶意用户下载服务器上的任何文件。请考虑<代码>下载.php。
.Plus…为什么要硬编码mime类型?它允许您处理服务器知道的任何mime类型。我只是在搜索一些解决方案,这是我找到并尝试使用的解决方案。那么,链接它可以做什么呢?而且它仍然不能解决我的输出问题:(我看不到实际的php代码。而且我的服务器肯定支持php。我的下载中的头文件是否可能与整个门户发送的头文件混合在一起?如果你看到的唯一一件事是文件本身,你可以浏览标记,那就不太可能了。)