public function testGetMimeByExtension() { $this->assertEquals('application/octet-stream', Utils::getMimeByExtension('')); $this->assertEquals('text/html', Utils::getMimeByExtension('html')); $this->assertEquals('application/json', Utils::getMimeByExtension('json')); $this->assertEquals('application/atom+xml', Utils::getMimeByExtension('atom')); $this->assertEquals('application/rss+xml', Utils::getMimeByExtension('rss')); $this->assertEquals('image/jpeg', Utils::getMimeByExtension('jpg')); $this->assertEquals('image/png', Utils::getMimeByExtension('png')); $this->assertEquals('text/plain', Utils::getMimeByExtension('txt')); $this->assertEquals('application/msword', Utils::getMimeByExtension('doc')); $this->assertEquals('application/octet-stream', Utils::getMimeByExtension('foo')); $this->assertEquals('foo/bar', Utils::getMimeByExtension('foo', 'foo/bar')); $this->assertEquals('text/html', Utils::getMimeByExtension('foo', 'text/html')); }
/** * Provides the ability to download a file to the browser * * @param string $file the full path to the file to be downloaded * @param bool $force_download as opposed to letting browser choose if to download or render * @param int $sec Throttling, try 0.1 for some speed throttling of downloads * @param int $bytes Size of chunks to send in bytes. Default is 1024 * @throws \Exception */ public static function download($file, $force_download = true, $sec = 0, $bytes = 1024) { if (file_exists($file)) { // fire download event Grav::instance()->fireEvent('onBeforeDownload', new Event(['file' => $file])); $file_parts = pathinfo($file); $mimetype = Utils::getMimeByExtension($file_parts['extension']); $size = filesize($file); // File size // clean all buffers while (ob_get_level()) { ob_end_clean(); } // required for IE, otherwise Content-Disposition may be ignored if (ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } header("Content-Type: " . $mimetype); header('Accept-Ranges: bytes'); if ($force_download) { // output the regular HTTP headers header('Content-Disposition: attachment; filename="' . $file_parts['basename'] . '"'); } // multipart-download and download resuming support if (isset($_SERVER['HTTP_RANGE'])) { list($a, $range) = explode("=", $_SERVER['HTTP_RANGE'], 2); list($range) = explode(",", $range, 2); list($range, $range_end) = explode("-", $range); $range = intval($range); if (!$range_end) { $range_end = $size - 1; } else { $range_end = intval($range_end); } $new_length = $range_end - $range + 1; header("HTTP/1.1 206 Partial Content"); header("Content-Length: {$new_length}"); header("Content-Range: bytes {$range}-{$range_end}/{$size}"); } else { $new_length = $size; header("Content-Length: " . $size); if (Grav::instance()['config']->get('system.cache.enabled')) { $expires = Grav::instance()['config']->get('system.pages.expires'); if ($expires > 0) { $expires_date = gmdate('D, d M Y H:i:s T', time() + $expires); header('Cache-Control: max-age=' . $expires); header('Expires: ' . $expires_date); header('Pragma: cache'); } header('Last-Modified: ' . gmdate("D, d M Y H:i:s T", filemtime($file))); // Return 304 Not Modified if the file is already cached in the browser if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= filemtime($file)) { header('HTTP/1.1 304 Not Modified'); exit; } } } /* output the file itself */ $chunksize = $bytes * 8; //you may want to change this $bytes_send = 0; $fp = @fopen($file, 'r'); if ($fp) { if (isset($_SERVER['HTTP_RANGE'])) { fseek($fp, $range); } while (!feof($fp) && !connection_aborted() && $bytes_send < $new_length) { $buffer = fread($fp, $chunksize); echo $buffer; //echo($buffer); // is also possible flush(); usleep($sec * 1000000); $bytes_send += strlen($buffer); } fclose($fp); } else { throw new \Exception('Error - can not open file.'); } exit; } }
/** * Set response header. */ public function header() { /** @var Page $page */ $page = $this['page']; $format = $page->templateFormat(); header('Content-type: ' . Utils::getMimeByExtension($format, 'text/html')); // Calculate Expires Headers if set to > 0 $expires = $page->expires(); if ($expires > 0) { $expires_date = gmdate('D, d M Y H:i:s', time() + $expires) . ' GMT'; header('Cache-Control: max-age=' . $expires); header('Expires: ' . $expires_date); } // Set the last modified time if ($page->lastModified()) { $last_modified_date = gmdate('D, d M Y H:i:s', $page->modified()) . ' GMT'; header('Last-Modified: ' . $last_modified_date); } // Calculate a Hash based on the raw file if ($page->eTag()) { header('ETag: ' . md5($page->raw() . $page->modified())); } // Set debugger data in headers if (!($format === null || $format == 'html')) { $this['debugger']->enabled(false); } // Set HTTP response code if (isset($this['page']->header()->http_response_code)) { http_response_code($this['page']->header()->http_response_code); } // Vary: Accept-Encoding if ($this['config']->get('system.pages.vary_accept_encoding', false)) { header('Vary: Accept-Encoding'); } }