From 2a06dc9bea3d91abbcdac37b84c62bfc795df0be Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 13:21:03 -0600 Subject: [PATCH 1/7] customizable page types --- system/config/system.yaml | 1 + system/src/Grav/Common/Uri.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/system/config/system.yaml b/system/config/system.yaml index 59f4b36a9..a5eec78fe 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -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 diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index d1dad9fda..3faa894a5 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -84,7 +84,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']; } From 7030422b11638d6fd859f63d8820e56b58087a30 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 13:21:23 -0600 Subject: [PATCH 2/7] New baseman option in Uri class --- system/src/Grav/Common/Uri.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index 3faa894a5..e2b7b6670 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -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; + } /** @@ -286,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 * From 4785103081cd725137e860bd4166236685b56f53 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 13:21:53 -0600 Subject: [PATCH 3/7] Added download() and getMimeType() static methods --- system/src/Grav/Common/Utils.php | 158 +++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index c82aabf33..6c5b99d33 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -231,4 +231,162 @@ 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)) { + $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"; + } + } } From 174672c4110adfc5119d59fd1f780cdbe3925c85 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 13:22:10 -0600 Subject: [PATCH 4/7] Support chunked downloads and non-media filetypes --- system/src/Grav/Common/Grav.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index e0a91a06a..57a749dec 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -99,32 +99,31 @@ 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']); + $media_file = urldecode($uri->basename()); + + // 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) { + foreach ($uri->query(null, true) as $action => $params) { if (in_array($action, Medium::$valid_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); } } From 01ce80fb1a1c152fc55e18f685b1bb755cbb87b2 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 13:30:36 -0600 Subject: [PATCH 5/7] fixed direct operations on media objects --- system/src/Grav/Common/Grav.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index 57a749dec..f6e23968b 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -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 @@ -111,13 +111,13 @@ class Grav extends Container $page = $c['pages']->dispatch($path_parts['dirname'], true); if ($page) { $media = $page->media()->all(); - $media_file = urldecode($uri->basename()); + $media_file = urldecode($path_parts['basename']); // if this is a media object, try actions first if (isset($media[$media_file])) { $medium = $media[$media_file]; foreach ($uri->query(null, true) as $action => $params) { - if (in_array($action, Medium::$valid_actions)) { + if (in_array($action, ImageMedium::$magic_actions)) { call_user_func_array(array(&$medium, $action), explode(',', $params)); } } From 21a65945739cb19e8b31c20b62f365a0c1ef7cfc Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 14:14:51 -0600 Subject: [PATCH 6/7] Added a onBeforeDownload() event to provide logging/access check, etc. --- system/src/Grav/Common/Utils.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/system/src/Grav/Common/Utils.php b/system/src/Grav/Common/Utils.php index 6c5b99d33..4d7163e35 100644 --- a/system/src/Grav/Common/Utils.php +++ b/system/src/Grav/Common/Utils.php @@ -1,6 +1,8 @@ fireEvent('onBeforeDownload', new Event(['file' => $file])); + $file_parts = pathinfo($file); $filesize = filesize($file); $range = false; From 8f54e5739f39fc8ae577a9c4765fbd7343049187 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Fri, 10 Apr 2015 14:28:37 -0600 Subject: [PATCH 7/7] fix for any file with parameters --- system/src/Grav/Common/Grav.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index f6e23968b..832c00e89 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -111,7 +111,10 @@ class Grav extends Container $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])) {