diff options
author | Andrey Andreev <narf@bofh.bg> | 2012-11-22 15:57:23 +0100 |
---|---|---|
committer | Andrey Andreev <narf@bofh.bg> | 2012-11-22 15:57:23 +0100 |
commit | 53fff911de3564c8688550452f138991730a704f (patch) | |
tree | 57b9845b0feba75184c2d88b35f4c8d4a8a99676 | |
parent | 93f5c5d2f9fc385c1617c125cfdf1822e6d7aee2 (diff) |
Added support for stream-like downloads of existing files to force_download()
Based on code/ideas from PR #365, #1254
-rw-r--r-- | system/helpers/download_helper.php | 41 | ||||
-rw-r--r-- | user_guide_src/source/changelog.rst | 6 | ||||
-rw-r--r-- | user_guide_src/source/helpers/download_helper.rst | 12 |
3 files changed, 49 insertions, 10 deletions
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php index 8fe66e222..31652d53e 100644 --- a/system/helpers/download_helper.php +++ b/system/helpers/download_helper.php @@ -56,6 +56,23 @@ if ( ! function_exists('force_download')) { return FALSE; } + elseif ($data === NULL) + { + if (@is_file($filename) && @file_exists($filename) && ($filesize = @filesize($filename)) !== FALSE) + { + $filepath = $filename; + $filename = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $filename)); + $filename = end($filename); + } + else + { + return FALSE; + } + } + else + { + $filesize = strlen($data); + } // Set the default MIME type to send $mime = 'application/octet-stream'; @@ -95,8 +112,13 @@ if ( ! function_exists('force_download')) $filename = implode('.', $x); } + if ($data === NULL && ($fp = @fopen($filepath, 'rb')) === FALSE) + { + return FALSE; + } + // Clean output buffer - if (ob_get_level() !== 0) + if (ob_get_level() !== 0 && @ob_end_clean() === FALSE) { ob_clean(); } @@ -106,7 +128,7 @@ if ( ! function_exists('force_download')) header('Content-Disposition: attachment; filename="'.$filename.'"'); header('Expires: 0'); header('Content-Transfer-Encoding: binary'); - header('Content-Length: '.strlen($data)); + header('Content-Length: '.$filesize); // Internet Explorer-specific headers if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) @@ -116,7 +138,20 @@ if ( ! function_exists('force_download')) header('Pragma: no-cache'); - exit($data); + // If we have raw data - just dump it + if ($data !== NULL) + { + exit($data); + } + + // Flush 1MB chunks of data + while ( ! feof($fp) && ($data = fread($fp, 1048576)) !== FALSE) + { + echo $data; + } + + fclose($fp); + exit; } } diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 6047f1c9c..e523c4cab 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -77,8 +77,10 @@ Release Date: Not Released - :doc:`Inflector Helper <helpers/inflector_helper>` changes include: - Changed :php:func:`humanize()` to allow passing an input separator as its second parameter. - Refactored :php:func:`plural()` and :php:func:`singular()` to avoid double pluralization and support more words. - - Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default). - - Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase. + - :doc:`Download Helper <helpers/download_helper>` changes include: + - Added an optional third parameter to :php:func:`force_download()` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default). + - Added a work-around in :php:func:`force_download()` for a bug Android <= 2.1, where the filename extension needs to be in uppercase. + - Added support for reading from an existing file path by passing NULL as the second parameter to :php:func:`force_download()` (useful for large files and/or safely transmitting binary data). - :doc:`Form Helper <helpers/form_helper>` changes include: - :php:func:`form_dropdown()` will now also take an array for unity with other form helpers. - :php:func:`form_prep()`'s second argument now only accepts a boolean value, which determines whether the value is escaped for a <textarea> or a regular <input> element. diff --git a/user_guide_src/source/helpers/download_helper.rst b/user_guide_src/source/helpers/download_helper.rst index 1e9ec21ea..860c568b9 100644 --- a/user_guide_src/source/helpers/download_helper.rst +++ b/user_guide_src/source/helpers/download_helper.rst @@ -21,7 +21,7 @@ force_download() .. php:function:: force_download($filename = '', $data = '', $set_mime = FALSE) :param string $filename: Filename - :param string $data: File contents + :param mixed $data: File contents :param bool $set_mime: Whether to try to send the actual MIME type :returns: void @@ -30,6 +30,9 @@ desktop. Useful with file downloads. The first parameter is the **name you want the downloaded file to be named**, the second parameter is the file data. +If you set the second parameter to NULL and ``$filename`` is an existing, readable +file path, then its content will be read instead. + If you set the third parameter to boolean TRUE, then the actual file MIME type (based on the filename extension) will be sent, so that if your browser has a handler for that type - it can use it. @@ -41,8 +44,7 @@ Example:: force_download($name, $data); If you want to download an existing file from your server you'll need to -read the file into a string:: +do the following:: - $data = file_get_contents('/path/to/photo.jpg'); // Read the file's contents - $name = 'myphoto.jpg'; - force_download($name, $data);
\ No newline at end of file + // Contents of photo.jpg will be automatically read + force_download('/path/to/photo.jpg', NULL);
\ No newline at end of file |