search for in the  
<popenreadlink>
Last updated: Thu, 19 May 2005

readfile

(PHP 3, PHP 4, PHP 5)

readfile -- Outputs a file

Description

int readfile ( string filename [, bool use_include_path [, resource context]] )

Reads a file and writes it to the output buffer.

Returns the number of bytes read from the file. If an error occurs, FALSE is returned and unless the function was called as @readfile(), an error message is printed.

Tip: You can use a URL as a filename with this function if the fopen wrappers have been enabled. See fopen() for more details on how to specify the filename and Appendix L for a list of supported URL protocols.

You can use the optional second parameter and set it to TRUE, if you want to search for the file in the include_path, too.

Note: Context support was added with PHP 5.0.0. For a description of contexts, refer to Reference CXXII, Stream Functions.

See also fpassthru(), file(), fopen(), include(), require(), virtual(), file_get_contents(), and Appendix L.



User Contributed Notes
readfile
Hernán Pereira
17-May-2005 01:21
I saw in previous contributed notes that in content-disposition the file is not a quoted-string, there is no problem if the filename have no spaces but if it has in IE it works but in Firefox not.

The RFC 2616 puts as an example this:
Content-Disposition: attachment; filename="fname.ext"

You can see http://www.faqs.org/rfcs/rfc2616.html section "19.5.1 Content-Disposition" for more details.

The correct header then is this:
header("Content-Disposition: attachment; filename=\"$filename\"");
Philipp Heckel
10-May-2005 06:58
To use readfile() it is absolutely necessary to set the mime-type before. If you are using an Apache, it's quite simple to figure out the correct mime type. Apache has a file called "mime.types" which can (in normal case) be read by all users.

Use this (or another) function to get a list of mime-types:

<?php

  
function mimeTypes($file) {
       if (!
is_file($file) || !is_readable($file)) return false;
      
$types = array();
      
$fp = fopen($file,"r");
       while (
false != ($line = fgets($fp,4096))) {
           if (!
preg_match("/^\s*(?!#)\s*(\S+)\s+(?=\S)(.+)/",$line,$match)) continue;
          
$tmp = preg_split("/\s/",trim($match[2]));
           foreach(
$tmp as $type) $types[strtolower($type)] = $match[1];
       }
      
fclose ($fp);
      
       return
$types;
   }

  
# [...]

   # read the mime-types
  
$mimes = mimeTypes('/usr/local/apache/current/conf/mime.types');

  
# use them ($ext is the extension of your file)
  
if (isset($mimes[$ext])) header("Content-Type: ".$mimes[$ext]);
  
header("Content-Length: ".@filesize($fullpath));
  
readfile($fullpath); exit;

?>

If you do not want to read from the mime.types file directly, you can of course make a copy in another folder!
Cheers Philipp Heckel
flobee at gmail dot com
06-May-2005 01:17
regarding php5:
i found out that there is already a disscussion @php-dev  about readfile() and fpassthru() where only exactly 2 MB will be delivered.

so you may use this on php5 to get lager files
<?php
function readfile_chunked($filename,$retbytes=true) {
  
$chunksize = 1*(1024*1024); // how many bytes per chunk
  
$buffer = '';
  
$cnt =0;
  
// $handle = fopen($filename, 'rb');
  
$handle = fopen($filename, 'rb');
   if (
$handle === false) {
       return
false;
   }
   while (!
feof($handle)) {
      
$buffer = fread($handle, $chunksize);
       echo
$buffer;
       if (
$retbytes) {
          
$cnt += strlen($buffer);
       }
   }
      
$status = fclose($handle);
   if (
$retbytes && $status) {
       return
$cnt; // return num. bytes delivered like readfile() does.
  
}
   return
$status;

}
?>
TheDayOfCondor
27-Apr-2005 08:24
I think that readfile suffers from the maximum script execution time. The readfile is always completed even if it exceed the default 30 seconds limit, then the script is aborted.
Be warned that you can get very odd behaviour not only on large files, but also on small files if the user has a slow connection.

The best thing to do is to use

<?
  set_time_limit
(0);
?>

just before the readfile, to disable completely the watchdog if you intend to use the readfile call to tranfer a file to the user.
comicforum at lelon dot net
22-Apr-2005 01:22
The problem with using readfile on large files isn't caused by your memory_limit setting.  Setting it to 4x the size of the file can still cause the file to be truncated.  Use the readfile_chunked found below.
TheDayOfCondor
20-Apr-2005 11:10
Beware - the chunky readfile suggested by Rob Funk can easily exceed you maximum script execution time (30 seconds by default).

I suggest you to use the set_time_limit function inside the while loop to reset the php watchdog.
php at cNhOiSpPpAlMe dot net
21-Feb-2005 08:25
For some reason, readfile seems to reset the file's modified time (filemtime). Using fopen and fpassthru avoids this.

<?
$fp
= @fopen($file,"rb");
fpassthru($fp);
fclose($fp);
?>

(PHP version: 4.3.10)
Rob Funk
04-Jan-2005 12:31
When using readfile() with very large files, it's possible to run into problems due to the memory_limit setting; apparently readfile() pulls the whole file into memory at once.

One solution is to make sure memory_limit is larger than the largest file you'll use with readfile().  A better solution is to write a chunking readfile.  Here's a simple one that doesn't exactly conform to the API, but is close enough for most purposes:

<?php
function readfile_chunked ($filename) {
 
$chunksize = 1*(1024*1024); // how many bytes per chunk
 
$buffer = '';
 
$handle = fopen($filename, 'rb');
  if (
$handle === false) {
   return
false;
  }
  while (!
feof($handle)) {
  
$buffer = fread($handle, $chunksize);
   print
$buffer;
  }
  return
fclose($handle);
}
?>
Justin Dearing
29-Dec-2004 05:38
Word for word copy of a comment on session_start() posted by Kevin. Might be relevant here.

If you're having a problem with a file download script not working with IE if you call session_start() before sending the file, then try adding a session_cache_limiter() call before session_start().

I use session_cache_limiter('none'), but 'public' and 'private' seem to fix the problem too; use whichever suits your application.
grey - greywyvern - com
29-Dec-2004 10:29
readfile() makes a handy include for what you know should be plain HTML or text.  Sloppy and/or lazy scripters can introduce security risks when using include() and require() in such a way that users can tell the script what file(s) to include.  This is because the PHP code contained in any file they refer to is executed with PHP's privledges.

With readfile(), any PHP code is passed to the output buffer as-is, without being executed.
ctemple at n-able dot com
15-Nov-2004 02:12
If you're passing files through a script, you may want to include this header:

       header ("Cache-Control: must-revalidate, post-check=0, pre-check=0");

Otherwise, some programs such as Adobe Reader may have problems opening files directly.

<?php
       header
("Cache-Control: must-revalidate, post-check=0, pre-check=0");
      
header ("Content-Type: application/octet-stream");
      
header ("Content-Length: " . filesize($theFile));
      
header ("Content-Disposition: attachment; filename=$theFileName");
      
readfile($theFile);
?>
Thomas Jespersen
25-Oct-2004 08:06
Remember if you make a "force download" script like mentioned below that you SANITIZE YOUR INPUT!

I have seen a lot of  download scripts that does not test so you are able to download anything you want on the server.

Test especially for strings like ".." which makes directory traversal possible. If possible only permit characters a-z, A-Z and 0-9 and make it possible to only download from one "download-folder".
flobee at gmail dot com
04-Oct-2004 07:33
you may try the statemants below with
header("Content-Type: application/octet-stream");
// insteat OF: header('Content-Type: application/force-download');
MAC OSX / IE: has problems to find the right mime type and do not accept spaces in filenames. then all plattforms should work
nobody at localhost
23-Sep-2004 04:03
If you want to force a download:

<?php
$file
= '/var/www/html/file-to-download.xyz';
header('Content-Description: File Transfer');
header('Content-Type: application/force-download');
header('Content-Length: ' . filesize($filename));
header('Content-Disposition: attachment; filename=' . basename($file));
readfile($file);
?>
kschenke at datafreight dot com
15-Oct-2003 11:43
If your site visitors are having problems with Internet Explorer downloading files over an SSL connection, see the manual page for the session_cache_limiter() function.

<popenreadlink>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 17:35:34 2005 CDT