Merge branch 'feature/improved_download_support' into develop

This commit is contained in:
Andy Miller
2015-04-11 18:27:09 -06:00
4 changed files with 200 additions and 15 deletions

View File

@@ -30,6 +30,7 @@ pages:
special_chars: # List of special characters to automatically convert to entities
'>': 'gt'
'<': 'lt'
types: 'txt|xml|html|json|rss|atom' # Pipe separated list of valid page types
cache:
enabled: true # Set to true to enable caching

View File

@@ -2,6 +2,7 @@
namespace Grav\Common;
use Grav\Common\Filesystem\Folder;
use Grav\Common\Page\Medium\ImageMedium;
use Grav\Common\Page\Pages;
use Grav\Common\Service\ConfigServiceProvider;
use Grav\Common\Service\ErrorServiceProvider;
@@ -10,7 +11,6 @@ use Grav\Common\Service\StreamsServiceProvider;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\Event\Event;
use RocketTheme\Toolbox\Event\EventDispatcher;
use Grav\Common\Page\Medium\Medium;
/**
* Grav
@@ -99,32 +99,34 @@ class Grav extends Container
/** @var Pages $pages */
$pages = $c['pages'];
// If base URI is set, we want to remove it from the URL.
$path = '/' . ltrim(Folder::getRelativePath($c['uri']->route(), $pages->base()), '/');
/** @var Uri $uri */
$uri = $c['uri'];
$path = $uri->path();
$page = $pages->dispatch($path);
if (!$page || !$page->routable()) {
// special case where a media file is requested
$path_parts = pathinfo($path);
$page = $c['pages']->dispatch($path_parts['dirname'], true);
if ($page) {
$media = $page->media()->all();
$media_file = urldecode($path_parts['basename']);
$parsed_url = parse_url(urldecode($uri->basename()));
$media_file = $parsed_url['path'];
// if this is a media object, try actions first
if (isset($media[$media_file])) {
$medium = $media[$media_file];
// loop through actions for the image and call them
foreach ($c['uri']->query(null, true) as $action => $params) {
if (in_array($action, Medium::$valid_actions)) {
foreach ($uri->query(null, true) as $action => $params) {
if (in_array($action, ImageMedium::$magic_actions)) {
call_user_func_array(array(&$medium, $action), explode(',', $params));
}
}
header('Content-type: '. $medium->get('mime'));
echo file_get_contents($medium->path());
die;
Utils::download($medium->path(), false);
} else {
Utils::download($page->path() . DIRECTORY_SEPARATOR . $uri->basename(), true);
}
}

View File

@@ -11,6 +11,7 @@ class Uri
{
public $url;
protected $basename;
protected $base;
protected $root;
protected $bits;
@@ -64,6 +65,7 @@ class Uri
$this->base = $base;
$this->root = $base . $root_path;
$this->url = $base . $uri;
}
/**
@@ -84,7 +86,11 @@ class Uri
// remove the extension if there is one set
$parts = pathinfo($uri);
if (preg_match("/\.(txt|xml|html|json|rss|atom)$/", $parts['basename'])) {
// set the original basename
$this->basename = $parts['basename'];
if (preg_match("/\.(".$config->get('system.pages.types').")$/", $parts['basename'])) {
$uri = rtrim($parts['dirname'], '/').'/'.$parts['filename'];
$this->extension = $parts['extension'];
}
@@ -282,6 +288,17 @@ class Uri
return $this->host();
}
/**
* Return the basename of the URI
*
* @return String The basename of the URI
*/
public function basename()
{
return $this->basename;
}
/**
* Return the base of the URI
*

View File

@@ -1,6 +1,8 @@
<?php
namespace Grav\Common;
use RocketTheme\Toolbox\Event\Event;
/**
* Misc utilities.
*
@@ -8,6 +10,8 @@ namespace Grav\Common;
*/
abstract class Utils
{
use GravTrait;
/**
* @param string $haystack
* @param string $needle
@@ -231,4 +235,165 @@ abstract class Utils
{
return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length);
}
/**
* Provides the ability to download a file to the browser
*
* @param $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
*/
public static function download($file, $force_download = true)
{
if (file_exists($file)) {
// fire download event
self::getGrav()->fireEvent('onBeforeDownload', new Event(['file' => $file]));
$file_parts = pathinfo($file);
$filesize = filesize($file);
$range = false;
set_time_limit(0);
ignore_user_abort(false);
ini_set('output_buffering', 0);
ini_set('zlib.output_compression', 0);
if ($force_download) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$file_parts['basename']);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
} else {
header("Content-Type: " . Utils::getMimeType($file_parts['extension']));
}
header('Content-Length: ' . $filesize);
// 8kb chunks for now
$chunk = 8 * 1024;
$fh = fopen($file, "rb");
if ($fh === false) {
return;
}
// Repeat reading until EOF
while (!feof($fh)) {
echo fread($fh, $chunk);
ob_flush(); // flush output
flush();
}
exit;
}
}
/**
* Return the mimetype based on filename
*
* @param $extension Extension of file (eg .txt)
*
* @return string
*/
public static function getMimeType($extension)
{
$extension = strtolower($extension);
switch($extension)
{
case "js":
return "application/x-javascript";
case "json":
return "application/json";
case "jpg":
case "jpeg":
case "jpe":
return "image/jpg";
case "png":
case "gif":
case "bmp":
case "tiff":
return "image/" . $extension;
case "css":
return "text/css";
case "xml":
return "application/xml";
case "doc":
case "docx":
return "application/msword";
case "xls":
case "xlt":
case "xlm":
case "xld":
case "xla":
case "xlc":
case "xlw":
case "xll":
return "application/vnd.ms-excel";
case "ppt":
case "pps":
return "application/vnd.ms-powerpoint";
case "rtf":
return "application/rtf";
case "pdf":
return "application/pdf";
case "html":
case "htm":
case "php":
return "text/html";
case "txt":
return "text/plain";
case "mpeg":
case "mpg":
case "mpe":
return "video/mpeg";
case "mp3":
return "audio/mpeg3";
case "wav":
return "audio/wav";
case "aiff":
case "aif":
return "audio/aiff";
case "avi":
return "video/msvideo";
case "wmv":
return "video/x-ms-wmv";
case "mov":
return "video/quicktime";
case "zip":
return "application/zip";
case "tar":
return "application/x-tar";
case "swf":
return "application/x-shockwave-flash";
default:
return "application/octet-stream";
}
}
}