public function serveFile($path, $mime_type, $download = false) { if (!file_exists($path)) { header('Content-Type: image/jpeg'); readfile(BASE_PATH . '/www/images/unavail.jpg'); exit; } $filename = basename($path); //from php.net $headers = apache_request_headers(); // Checking if the client is validating its cache and if it is current. if (isset($headers['If-Modified-Since']) && strtotime($headers['If-Modified-Since']) == filemtime($path)) { // Client's cache IS current, so we just respond '304 Not Modified'. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT', true, 304); } else { // Image not cached or cache outdated, we respond '200 OK' and output the image. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT', true, 200); header('Content-Length: ' . filesize($path)); header('Content-Type: ' . $mime_type); //hack to deal w/ iPad that only wants byte ranges if ('video/mp4' == $mime_type) { Dase_Util::rangeDownload($path); exit; } if ('audio/mpeg' == $mime_type) { Dase_Util::rangeDownload($path); exit; } if ($download) { header("Content-Disposition: attachment; filename={$filename}"); //from http://us.php.net/fread $total = filesize($path); $blocksize = 2 << 20; //2M chunks $sent = 0; $handle = fopen($path, "r"); // Now we need to loop through the file and echo out chunks of file data while ($sent < $total) { echo fread($handle, $blocksize); $sent += $blocksize; } } else { header("Content-Disposition: inline; filename={$filename}"); //print file_get_contents($path); Dase_Util::readfileChunked($path); } } exit; }