Search This Blog

Monday, May 10, 2010

Reading Entire Files

There are also some functions that provide access to the complete contents of files in one go. These include:
  • file()
  • fpassthru()
  • readfile()
The file() function takes just one argument: a string containing the name of a file. For example:


file("/home/chris/myfile.txt")

returns the entire contents of myfile.txt (in the directory /home/chris/) as an array, using the newline character (CR LF on the Windows platform) to delimit elements. The newline character remains attached at the end of each line stored in the array. This function doesn't require you to specify a file handle because you can refer to the filename explicitly; it automatically opens, reads, and, once it's done, closes the file.


Here's the file() version of the original hit counter:


<?php
//hit_counter06.php
$counter_file = "./count.dat";
$lines = file($counter_file);
$counter = (int) $lines[0];

$counter++;

echo "You're visitor No. $counter.";

if(!($fp = fopen($counter_file, "w"))) die ("Cannot open $counter_file.");
fwrite($fp, $counter);
fclose($fp);
?>

The entire contents of the data file are read into the array $lines and only the first element of the array (the first line of the file) is extracted. You could actually do just the same using a mixture of feof() and fgets() like this:


$fp = fopen ("./count.dat", "r");
while (!feof($fp)) $lines[] = fgets($fp, 1024);
fclose ($fp);

But you don't need to because the file() function does it all for you. As with fopen(), it can also fetch files on a remote host:


$file_lines = file( "http://www.whatyoumaycallit.com/index.html" );
foreach($file_lines as $line) echo $line;

Although this function can be very useful for reading the entire contents of a file, you should exercise caution when using it—if it tries to read a very large file, it may end up consuming all the memory allocated to PHP. That wouldn't be a good move.


The fpassthru() function is the one to use if all you want to do is read and print the entire file to the Web browser. It takes a single argument, a file handle, which it uses to read the remaining data from a file (that is, from the current position until end-of-file). It then writes results to standard output. Here's the corresponding version of the hit counter:


<?php
//hit_counter07.php
$counter_file = ./count.dat";
if(!($fp = fopen($counter_file, "r"))) die ("Cannot open $counter_file.");
$counter = (int) fread($fp, 20);
fclose($fp);

$counter++;

if(!($fp = fopen($counter_file, "w"))) die ("Cannot open $counter_file.");
fwrite($fp, $counter);
fclose($fp);

if(!($fp = fopen($counter_file, "r"))) die ("Cannot open $counter_file.");
echo "You're visitor No. ";
fpassthru($fp);
?>

Only data from the current file position onward is written. If you read a couple of lines from a file before calling fpassthru(), for example, only the subsequent contents of the file will be printed. The file is closed when the function finishes reading, so there's no need to call fclose()—in fact, if you do, you get a warning that the file pointer is not valid.


The readfile() function enables you to print the contents of a file without even having to call fopen(). It takes a filename as its single argument, reads the whole file, and then writes it to standard output, returning the number of bytes read (or False upon error). Apply it like this:


<?php
//hit_counter08.php
$counter_file = "./count.dat";
if(!($fp = fopen($counter_file, "r"))) die ("Cannot open $counter_file.");
$counter = (int) fread($fp, 20);
fclose($fp);

$counter++;

if(!($fp = fopen($counter_file, "w"))) die ("Cannot open $counter_file.");
fwrite($fp, $counter);
fclose($fp);

echo "You're visitor No. " ;
readfile($counter_file);
?>

As in the previous script, all read and write operations on the data file take place before the incremented counter is echoed out.