1

I am trying to get this code to work but for some reason, all the echo's are able to output correct content, but the headers don't seem to want to force the download of my document. What follows is the file I am trying to build for file downloads. It is set to input code like this: downloader.php?f=13&t=doc to download a file that is named 201-xxx.doc or 201-xxx.pdf from one of two folders depending on the users privileges.

All the logic works up to the header info at the bottom. If I comment out the header content type and the header content disposition, then it will read the file into the browser. With either of those lines included, it give me an error that says "Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found."

<?php
//ob_start();
if ( !defined('__DIR__') ) define('__DIR__', dirname(__FILE__));
define( "TLOJ_FSROOT", __DIR__ . "/" );
define('WP_USE_THEMES', false);
require('./wp-blog-header.php');

$lessonnumber = $_REQUEST['f'];
$type = $_REQUEST['t'];

    if ( $lessonnumber < '10' ) { $threedigitlesson = '00' . $lessonnumber; }
    elseif ( $lessonnumber < '100' ) { $threedigitlesson = '0' . $lessonnumber; }
    else { $threedigitlesson = $lessonnumber; }
    $filenamestart = "201-" . $threedigitlesson;

    $contenttype = 'application/octet-stream';

    switch ($type) {
        case 'pdf':
            $extension = '.' . $type;
            $contenttype = 'application/pdf';
            break;
        case 'doc':
            $extension = '.' . $type;
            $contenttype = 'application/msword';
            break;
        default:
            $contenttype = '';
            exit("It appears that you are trying to download a file that is not a lesson document. Please contact us if you believe this to be an error.");
    }

$filename = $filenamestart . '.' . $type;
$current_user = wp_get_current_user();

//$siteurl = site_url();
$pathroot = TLOJ_FSROOT;

$download_path = $pathroot . "1hoefl4priaspoafr/";
    if ( current_user_can("access_s2member_ccap_extendedlessons")) { 
        $download_path = $download_path . "ex/";
    } else {
        $download_path = $download_path . "st/";
    }

$file_path = $download_path . $filename;

$tlojmemberlength = tlojunlocklessons();

if ( !is_user_logged_in() ) { exit("Please log in to access the file"); }

if ( !current_user_can("access_s2member_ccap_downloadlessons") ) { exit("You don't have access to download the lessons!"); }

if ( $lessonnumber > $tlojmemberlength ) { exit("It appears you are trying to jump ahead! While I am excited at your enthusiam, let's not rush our study time."); }

if ( ($lessonnumber > '195') && (!current_user_can("access_s2member_ccap_lastweek")) ) { exit("Upgrade now to access the downloads for the five bonus lessons!"); }

// build Final File Name
$extendedmessage = "";
if ( current_user_can("access_s2member_ccap_extendedlessons")) { $extendedmessage = " - Extended"; }
$myfinishedlessonname = "Lesson " . $lessonnumber . $extendedmessage . " -- The Life of Jesus Study" . "." . $type;

//  echo 'Download Path: ' . $download_path . '<br />';
//  echo 'Source/Lesson Number: ' . $lessonnumber . '<br />';
//  echo 'File Name: ' . $filename . '<br />';
//  echo 'File Type: ' . $type . '<br />';
//  echo 'Allowed Lessons: ' . $tlojmemberlength . '<br />';
//  echo 'Final File Name: ' . $myfinishedlessonname . '<br />';
//  echo 'File Path: ' . $file_path . '<br />';
//  echo 'Content Type: ' . $contenttype . '<br />';
//  echo 'File Size: ' . filesize($file_path) . '<br />';

if (headers_sent()) { exit("Sorry but the headers have already been sent."); }

    ob_end_clean();

if (file_exists($file_path)) {
    header('Content-Description: File Transfer');
    header('Content-type: ' . $contenttype);
    header('Content-disposition: attachment; filename="' . $myfinishedlessonname . '"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: ');
    header('Pragma: ');
    header('Content-Length: ' . filesize($file_path));
    flush();
    ob_clean();
    readfile($file_path);
    exit;
} else { exit("No file present."); }


?>

Please help as I have been at this all day and am confused to no end why this won't work. Filesize() pulls the correct length so I know there is a file in the path that I am looking at. (I am also new to PHP, so if there is something that I am missing, please share.)

Thanks in advance!

Crazycoolcam
  • 321
  • 1
  • 4
  • 12
  • You'd be safer using `is_readable()` rather than `file_exists()`. is_readable both ensures that the file exists AND that it can be read. There's many files that exist, but can't be read. Also, what's in `$file_path` when you invoke readfile? – Marc B Nov 07 '11 at 01:24
  • Just saw this comment/question. I switched over to `is_readable()` and it still throws the error. When I uncomment the $file_path, it echos this: `/home5/[my host account]/public_html/1hoefl4priaspoafr/ex/201-015.pdf` which is the correct directory for the file. – Crazycoolcam Nov 07 '11 at 11:50

5 Answers5

10

If it's a big file, it cannot be sent with readfile. Try to use this:

  $handle = fopen($file_path, 'rb'); 
  $buffer = ''; 
  while (!feof($handle)) { 
    $buffer = fread($handle, 4096); 
    echo $buffer; 
    ob_flush(); 
    flush(); 
  } 
  fclose($handle); 
samura
  • 4,375
  • 1
  • 19
  • 26
  • by big file do you mean larger than 1 meg. All my PDFs and DOCs are less than 100k. Should I replace the headers with this block of text? – Crazycoolcam Nov 06 '11 at 23:53
  • I tried replacing just the readfile line and the error still showed up. I also tried commenting out all the header lines in favor of this code and it flowed the file in the browser. – Crazycoolcam Nov 06 '11 at 23:56
  • Big thanks! To have your code portable its a must to have ob_flush and flush called. I spent 3h searching why function doesnt work :) tnx! – Miha Trtnik Feb 22 '12 at 15:43
  • 1
    This is unnecessary. The "problem" with using readfile (which works fine) is forgetting to disable the output buffer (ie. not calling ob_clean_end first). See my comments http://stackoverflow.com/a/21936954/2864740 for details. – user2864740 Jul 08 '15 at 17:27
3

I am not sure why this worked, but I was able to solve this issue by breaking my php file into two pieces. Piece 1 loads WordPress and performs the logic validation. Then file 1 passes the information over to file 2 to do the download logic and write the header information.

Like I said, I am not sure why this worked, however a friend who knows PHP better than I do said that sometimes if the script takes too long to process then the headers won't take. It is possible that WordPress was hanging the script too long for these headers.

Hopefully this explanation will help someone else who is having this difficulty.

Crazycoolcam
  • 321
  • 1
  • 4
  • 12
2

If you are trying to force browser to download the file with the use of

Content-Type: application/octet-stream
Content-Disposition: attachment; filename="your-file.jpg"

but Chrome gives you ERR_FILE_NOT_FOUND and Firefox also fails with "Not found" (strangely Opera seems to work) try adding:

header('HTTP/1.0 200 OK', true, 200);

Kamil Szot
  • 17,436
  • 6
  • 62
  • 65
  • This fixed my problem. I guess it's because I'm handling this in a URL rewrite so technically the status defaults to 404, and then this sets it correctly to 200. – Philip Nov 13 '13 at 15:55
0

Chrome was telling me: "Error 6 (net::ERR_FILE_NOT_FOUND): The file or directory could not be found." And Firefox as saying the file did not exist.

Although the same php file was handling a different type of download I was having issues with PNG and ICO, I tried some methods that only displayed the picture but did not prompt for a download box.

Finally I found out thanks to Crazycoolcam, that Wordpress was the issue. I was including a php to a file I had called "tools.php", inside of tools.php it had an include to wordpress's main header file, to remedy the issue I split my tools file into a wordpress version and a non wordpress version and included the wordpress half after it had written the file out.

CTS_AE
  • 12,987
  • 8
  • 62
  • 63
  • Glad to see that this worked out for you. I have since tweaked my set of two files some, but the solution is still two files. I also just found out that wordpress uses its own series of tags and `?s=xx` does not work because I believe WordPress uses the `s` variable. I haven't dug into learning which letter combinations are bad, but I know there are a few. Glad that you are up and running again and this helped solve your problem. – Crazycoolcam Sep 12 '12 at 11:21
  • If you are trying to force browser to download the file with the use of `Content-Type: application/octet-stream Content-Disposition: attachment; filename="your-file.jpg"` but Chrome gives you **ERR_FILE_NOT_FOUND** and Firefox also fails with "Not found" (strangely Opera seems to work) try adding: `header('HTTP/1.0 200 OK', true, 200);` – Kamil Szot Jul 31 '13 at 00:30
0

Just another possibility here as to why its not working. This was the cause for me. Interestingly, file_exists was returning true but no form of serving the file to the public for download was working without having the below set correctly.

PHP has a setting called open_basedir

Make sure this is set correctly relevant to your hosting environment. open_basedir can be edited via php.ini

3rdLion
  • 159
  • 2