PHP 下载 PDF 总是导致不支持的文件类型损坏文件


PHP Download PDF always results in not supported file type of damaged file

我正在尝试允许我网站的用户下载文件。不仅如此,我还想将其烘焙到我创建/正在使用的前端控制器框架中。我可以进行下载,但是当尝试打开文件时,Adobe Reader总是给出一个错误,指出该文件的类型不受支持或已损坏。在我的下载中,它说文件的大小是0KB,这显然是错误的,所以我想它正在损坏。我不知道为什么。

我可以让下载工作,但跳过我的前端控制器框架,只是让它直接运行下载脚本。此脚本如下所示,称为 downloadManager.php并从带有 href="/myApp/downloads/downloadManager.php 的链接调用:

<?php
 header("Content-Type: application/octet-stream");
$file = "eZACKe_1359081853_Week Three Sprints & Hurdles Workout 24th - 28th of Sept    (1).pdf";
header("Content-Disposition: attachment; filename=" . $file);
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
 header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush(); // this doesn't really matter.
$fp = fopen($file, "r");
while (!feof($fp)) {
    echo fread($fp, 65536);
    flush(); // this is essential for large downloads
}
fclose($fp);
?>

这有效,但我想让我的框架正常工作。这是使用我的框架的代码流,链接 href 是 href="/myApp/downloadz?type='resume'&id='8'":

url 被 apache 重写并转到索引.php这是我的前端控制器:

<?php
class Foo {
static public function test($classname)
{
    if(preg_match('/''''/', $classname))
    {
        $path = str_replace('''', '/', $classname);
    }
    else
    {
        $path = str_replace('_', '/', $classname);
    }
    if (is_readable($path.".php"))
    {
        require_once $path .".php";
    }
}
}
spl_autoload_register(''Foo::test');
'controller'Controller::run();
?>

这导致一个控制器:

static function run()
{
    $instance = new Controller();
    $instance->init();
    $instance->handleRequest();
}

init 设置了一个 PDO MySQL 连接,并使用 Simple_XML_Load 加载一些配置文件

然后

    function handleRequest()
{
    $request = new 'controller'Request();
    $cmd_r = new 'commands'common'CommandResolver();
    $cmd = $cmd_r->getCommand($request);
    $presenter = $cmd->execute($request);
    if(!$request->getProperty('ajax') && !is_a($cmd, ''commands'Download'DownloadCommand')) {
        echo $this->handleRender($request, $presenter);
    }
}

这里唯一需要注意的是 getCommand 并检查文件是否存在并使用反射

因此,调用$cmd->execute,此时我们调用DownloadzCommand::execute,

    function execute('controller'Request $request) {
    parent::execute($request);
    if($this->request->getProperty("type") == "resume" || $this->request->getProperty("type") == "coverLetter") {
        $this->handleJobApplicationDownload();
    }
}
private function handleJobApplicationDownload() {
    if(!$this->loggedInMember) {
        exit;
    }
    try {
        $idobj = new 'mapper'IdentityObject ();
        $jobApplication = 'domain'JobApplication::produceOne($idobj->field("jobApplication.jobApplicationId")->eq($this->request->getProperty("id"))->field("jobApplication.jobId")->eq("jobs.jobId", false)->field("businesses.businessId")->eq("jobs.businessId", false)->field("jobApplication.dateApplicationViewed")->isnull("", false), null, "JobBusinessJoin");
        // get here the jobApplication is legit - now make sure the logged in member is a recruiter for this business
        $idobj = new 'mapper'IdentityObject ();
        $business = 'domain'Business::produceOne($idobj->field("businessId")->eq($jobApplication->getState("businessId")));
        if(!$business->isRecruiter($this->loggedInMember->getId())) {
            exit;
        } else {
            if($this->request->getProperty("type") == "resume") {
                if($path = $jobApplication->getState("resumeUploadPath")) {
                    // have a resume path, move it over
                    $fullPath = "common/jobs/resumes/".$path;
                    $tempDest = "commands/Downloadz/$path";
                    copy($fullPath, $tempDest);
                } else {
                    exit;
                }
            } elseif($this->request->getProperty("type") == "coverLetter") {
                if($path = $jobApplication->getState("coverLetterUploadPath")) {
                    // have a coverLetter path, move it over
                    $fullPath = "common/jobs/coverLetters/".$path;
                } else {
                    exit;
                }
            }
        }
    } catch('base'ObjectDoesNotExistException $e) {
        echo "nope";
    }

    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=" . $path);
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");
    header("Content-Description: File Transfer");
    header("Content-Length: " . filesize($path));
    flush(); // this doesn't really matter.
    $fp = fopen($file, "r");
    while (!feof($fp)) {
        echo fread($fp, 65536);
        flush(); // this is essential for large downloads
    }
    fclose($fp);
    unlink($path);
}

此时,下载将发生。我打开文件,但它已损坏。

请注意,即使对于简单的文本文件也会发生同样的事情。

此外,即使我跳过文件复制部分并且只是将文件最初放在命令/Downloadz 目录中,它也不起作用。

有什么想法吗?

而不是使用:

$fp = fopen($file, "r");
while (!feof($fp)) {
    echo fread($fp, 65536);
    flush(); // this is essential for large downloads
}
fclose($fp);

使用readfile()

readfile($file);

我遇到了同样的问题,但在阅读 http://davidwalsh.name/php-force-download 后,现在正在工作。

header('Pragma: public');  // required
header('Expires: 0');  // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Type: application/pdf');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($filepath)) . ' GMT');
header('Content-disposition: attachment; filename=' . $pathinfo['filename'] . '.pdf');
header("Content-Transfer-Encoding:  binary");
header('Content-Length: ' . filesize($filepath)); // provide file size
header('Connection: close');
readfile($filepath);
exit();

这对我有用。