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

▼魔方 西西 提交于 2020-01-25 07:14:05

问题


I'm trying to allow the user of my site to download files. More than this, I'd like to bake this into a Front Controller framework that I've created/am using. I can get the download to occur but when trying to open the file Adobe Reader always gives an error saying the file is of an unsupported type or it is damaged. In My Downloads it says the size of the file is 0KB which is obviously wrong, so it is getting damaged I guess. I don't know why though.

I CAN get the download to work but skipping my Front Controller framework and just having it directly run a download script. This script looks like this and is called downloadManager.php and is called from a link with 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);
?>

This works, but I'd like to keep my framework working. This is the code flow using my framework, with link href being href="/myApp/downloadz?type='resume'&id='8'":

The url gets rewritten by apache and goes to index.php which is my front controller:

<?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();
?>

Which leads to a Controller:

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

init sets up a PDO MySQL connection, and also loads some config files using Simple_XML_Load

Then,

    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);
    }
}

Only thing to note here is getCommand and checks if files exist and uses reflection

So then $cmd->execute is called and at this point we call 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);

}

And at this point the download occurs. I open the file though, and it is damaged.

A note, same thing happens even for a simple text file.

Also, it also doesn't work even if I skip the file copying part and just have the file originally in commands/Downloadz directory.

Any ideas?


回答1:


Instead of using:

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

Use readfile()

readfile($file);



回答2:


I had the same problem but after reading http://davidwalsh.name/php-force-download, now is working.

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();

This works for me.



来源:https://stackoverflow.com/questions/14538786/php-download-pdf-always-results-in-not-supported-file-type-of-damaged-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!