Whatevah
Whatevah

Reputation: 7

cURL using PHP: download file to client results in minorly corrupt file

Using the script I will post below, I successfully download JPG, PNG or PPT(x) files from server to the client using cURL in PHP. However, when I open any of the powerpoint files I save in this manner I get an error "PowerPoint found a problem with content in FILENAME.pptx. Powerpoint can attempt to repair the presentation. If you trust the source of this presentation, click Repair."

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 
}

Am I not closing the stream correctly? I don't know what the problem is.

Notes: JPG and PNG files open fine. & Clicking on "repair" successfully opens the file.

Upvotes: 1

Views: 1009

Answers (1)

dynamic
dynamic

Reputation: 48101

Acutally managing file download from the script isn't a good idea. Since your files are on your webserver it's better if you use a more robust approach such as: x_sendfile mod for apache:

https://tn123.org/mod_xsendfile/ ref

Usage:

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

Also, with your script you are giving away the possibility to pause and resume the download (you should manually manage Range and Content-Range header, and this is error-prone).

Upvotes: 1

Related Questions