Skip to content

Loading…

Pass thru feature added to download helper #365

Closed
wants to merge 2 commits into from

4 participants

@netcore2k

A small additional feature has been added to the download helper so that you can pass thru a file to the output. This method has better performance. All original functionality remains and is backwards compatible.

@netcore2k netcore2k A small additional feature has been added to the download helper so t…
…hat you can pass thru a file to the output. This method has better performance. All original functionality remains and is backwards compatible.
45ab0b8
@netcore2k

Inside PHP the readfile() method will attempt to memory map the file and do direct copy to output stream. If for whatever reason it cannot be memory mapped. For instance if the file is larger than what PHP can allocate it will buffer smaller amounts and push it through that way. Still never once using PHP objects only native C/C++.

@derekjones

Without exit()ing after pushing the file, don't you stand the chance that the application will continue to output content, resulting in a malformed file?

@netcore2k

Correct. I also noticed another issue. Sorry, this is what I get for reworking the code to CI standards at 4am. I'll make the corrections.

@netcore2k

I have some other changes to CI that would benefit others. Things like SSL for the xmlrpc library, other misc SSL support. I will gather them all together tomorrow and commit them all at once and send another pull request.

@it-can

Wil this also work with large files? Without memory problems?

@netcore2k

Yes. As mentioned above if it can't memory map the while file into memory it will push it in smaller chunks to the browser.

@netcore2k

I'm making further changes to take advantage of mod_xsendfile module for apache, which means less overhead for sending REALLY large files. By using the http "X-Sendfile:" response header. The module the pipes the file directly from apache after the PHP instance has finished.

@netcore2k netcore2k closed this
@netcore2k netcore2k reopened this
@it-can

Also for xsendfile for nginx?

@netcore2k

Sure I'll add support for nginx it simple uses the X-Accel-Redirect header instead.

@it-can

Cool

@narfbg narfbg added a commit that referenced this pull request
@narfbg narfbg Added support for stream-like downloads of existing files to force_do…
…wnload()

Based on code/ideas from PR #365, #1254
53fff91
@narfbg

Implemented, see the above commit.

@narfbg narfbg closed this
@nonchip nonchip pushed a commit to nonchip/CodeIgniter that referenced this pull request
@narfbg narfbg Added support for stream-like downloads of existing files to force_do…
…wnload()

Based on code/ideas from PR #365, #1254
13d317f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 1, 2011
  1. @netcore2k

    A small additional feature has been added to the download helper so t…

    netcore2k committed
    …hat you can pass thru a file to the output. This method has better performance. All original functionality remains and is backwards compatible.
  2. @netcore2k
This page is out of date. Refresh to see the latest.
Showing with 39 additions and 13 deletions.
  1. +29 −7 system/helpers/download_helper.php
  2. +10 −6 user_guide/helpers/download_helper.html
View
36 system/helpers/download_helper.php
@@ -35,17 +35,24 @@
* @access public
* @param string filename
* @param mixed the data to be downloaded
+ * @param bool determines wether data is a filepath to the actual data
* @return void
*/
if ( ! function_exists('force_download'))
{
- function force_download($filename = '', $data = '')
+ function force_download($filename = '', $data = '', $is_filepath = FALSE)
{
if ($filename == '' OR $data == '')
{
return FALSE;
}
-
+
+ // Test if the file exists if we are trying to use filepath
+ if ($is_filepath === TRUE AND file_exists($data) === FALSE)
+ {
+ return FALSE;
+ }
+
// Try to determine if the filename includes a file extension.
// We need it in order to set the MIME type
if (FALSE === strpos($filename, '.'))
@@ -76,7 +83,10 @@ function force_download($filename = '', $data = '')
{
$mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
}
-
+
+ // Get content length
+ $length = ($is_filepath === TRUE) ? filesize($data) : strlen($data);
+
// Generate the server headers
if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
{
@@ -86,7 +96,7 @@ function force_download($filename = '', $data = '')
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
- header("Content-Length: ".strlen($data));
+ header("Content-Length: ".$length);
}
else
{
@@ -95,13 +105,25 @@ function force_download($filename = '', $data = '')
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
- header("Content-Length: ".strlen($data));
+ header("Content-Length: ".$length);
}
- exit($data);
+ // Flush headers so browser can response immediately
+ flush();
+
+ // Push thru download content
+ if ($is_filepath === TRUE)
+ {
+ readfile($data, FALSE);
+ exit();
+ }
+ else
+ {
+ exit($data);
+ }
}
}
/* End of file download_helper.php */
-/* Location: ./system/helpers/download_helper.php */
+/* Location: ./system/helpers/download_helper.php */
View
16 user_guide/helpers/download_helper.html
@@ -69,11 +69,14 @@
<p>The following functions are available:</p>
-<h2>force_download('<var>filename</var>', '<var>data</var>')</h2>
+<h2>force_download('<var>filename</var>', '<var>data</var>', '<var>is_filepath</var>')</h2>
<p>Generates server headers which force data to be downloaded to your desktop. Useful with file downloads.
The first parameter is the <strong>name you want the downloaded file to be named</strong>, the second parameter is the file data.
-Example:</p>
+The third parameter determines wether or not the data parameter is to be interpreted as file data itself (default) or a
+file path to where the data can be located.</p>
+
+<p>Example:</p>
<code>
$data = 'Here is some text!';<br />
@@ -82,13 +85,14 @@
force_download($name, $data);
</code>
-<p>If you want to download an existing file from your server you'll need to read the file into a string:</p>
+<p>If you want to download an existing file from your server you should use the third parameter:</p>
+<p>When using this method the file will be pushed to the output from disk in the most optimal way.</p>
<code>
-$data = file_get_contents("/path/to/photo.jpg"); // Read the file's contents<br />
+$data = '/path/to/photo.jpg';<br />
$name = 'myphoto.jpg';<br />
<br />
-force_download($name, $data);
+force_download($name, $data, true);
</code>
@@ -109,4 +113,4 @@
</div>
</body>
-</html>
+</html>
Something went wrong with that request. Please try again.