ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


PHP Foundations Working with Files in PHP, Part Two

by John Coggeshall
12/12/2002

Welcome back to PHP Foundations. Last time I introduced you to the basic file access methods available to PHP: fopen(), fputs(), and fgets(). Although very useful, these functions work only with strings. This week I'll introduce to you more advanced file access functions that read and write binary files. We'll talk about fread() (used for reading), fseek() (used to find specific parts of a given file), along with a few other useful file access functions.

Basic Binary File I/O

As you may recall from my last column, PHP provides two fundamental functions for reading and writing text-based data. You'll be happy to know that when working with binary files, three of the functions you learned last time are still useful. We'll use fopen() to open our files, fclose() to close them, and fputs() / fwrite() to write data to the appropriate file.

fputs(), although it wasn't discussed earlier, is really an alias for the function fwrite(). There is no difference between the two functions; the different names follow the convention established in other programming languages. If you feel more comfortable with fputs() instead of fwrite(), use it without consequence. However, it is good practice to use fwrite() when dealing with binary data and fputs() for text, especially if you are doing both at the same time.

Related Reading

PHP Cookbook
By David Sklar, Adam Trachtenberg

Reading Binary data from a file

You'll notice that one function that I am not revisiting this week is the fgets() function. When working with binary data, you need a function named fread(). Like fgets(), the fread() function accepts two parameters:

fread($file_reference, $length);

Note that, unlike fgets(), fread() requires the $length parameter (the number of bytes to read from the file) to be specified. Upon success this function will return a string representation of the binary data read from the file or false (null) upon failure. How would you use this function to read binary data from a file? Here's a quick example.

<?php
   $fr   = fopen('/path/to/myfile.dat', 'r');
   $data = fread($fr, 1024);
   fclose($fr);
?>

On systems running PHP which differentiate between binary and text files (such as Windows), you'll need to open the file in binary mode by including b along with any other modes that you may require. To read a file on a Windows system using binary mode you'd use rb instead of the r you'd use on a UNIX-compatible system. Also, if you have "magic quotes" enabled, fread() may not function as expected (especially when dealing with a null character). PHP will automatically convert the "null" character to its escaped version \0 in the resulting input. Toggling "magic quotes" can be done by using the set_magic_quotes_runtime() and get_magic_quotes_runtime() functions whose information is available in the PHP manual.

Also in PHP Foundations:

Using MySQL from PHP, Part 2

Using MySQL from PHP

MySQL Crash Course, Part 3

MySQL Crash Course, Part 2

MySQL Crash Course

As you might expect, these code snippets read one kilobyte (1024 bytes) from the file referred to by $fr. Although this works just fine in a large file of hundreds of thousands (if not millions) of bytes, it works sequentially. Accessing a specific part of the file would be a matter of reading and discarding everything up to that point. Writing is more difficult. For instance, how would you read the 1,432,342nd byte from a file? What about writing a byte in the middle of a binary file? Both of these tasks can be solved using the fseek() function.

Moving the pointer within a file

In order to solve the problem of accessing a specific location within a file, we'll need a way to adjust the file pointer. What is a file pointer? It's the marker used by PHP to keep track of where the currently executing file operations take place. For instance, when a file is first created the file pointer is adjusted to the beginning of the file. Likewise, when a file is opened in append mode, the file is opened and the pointer points to the very end of the file. The fseek() function allows us to adjust the file pointer to anywhere within the file.

When using fseek() where the file pointer is placed (called an offset) is done in reference to one of three different locations: the beginning of the file, the end of the file, or the current pointer location. In PHP, these locations are represented by constants as shown below:

PHP ConstantFile Offset
SEEK_SETStarting from the beginning of the file
SEEK_CURStarting from the current pointer location
SEEK_ENDStarting from the end of the file

To use these constants, we need to understand how the fseek() function works. Its syntax is

fseek($file_reference, $offset, [$reference_point]);

where $file_reference represents the value returned by fopen(), and $offset represents the number of bytes to adjust the file pointer by starting from either $reference_point, if provided, or SEEK_SET if omitted. When executed, fseek() returns zero (0) upon success or negative one (-1) upon failure.

Let's take a look at a few examples. Assume the file being opened exists and is one kilobyte (1024 bytes) in size:

<?php
   $fr = fopen('/myfile.dat', 'r');
   echo "File opened, pointer is at start of file (SEEK_SET)<BR>";

   fseek($fr, 512);
   $byte = fread($fr, 1);
   echo "The byte is: $byte<BR>";
   echo "Pointer is now midway through the file (SEEK_SET+512)<BR>";

   fseek($fr, -256, SEEK_CUR);
   $byte = fread($fr, 1);
   echo "The byte is: $byte<BR>";
   echo "Pointer is now a fourth through the file (SEEK_SET+256)<BR>";

   fseek($fr, 1024, SEEK_CUR);
   $byte = fread($fr, 1);
   echo "The byte is: $byte<BR>";
   echo "Seek failed, 256+1024 is greater than the file size. 
         (still at SEEK_SET+256)";

   fseek($fr, -1024, SEEK_END);
   $byte = fread($fr, 1);
   echo "The byte is: $byte<BR>";
   echo "Back at start of file. (SEEK_END-1024 equals SEEK_SET)<BR>";

   $byte = fread($fr, 1);
   echo "The byte is: $byte<BR>";
   fclose($fr);
?>

Although here we elected to read from our file, this example could have been just as easily applied to write data at specific points within the file by using fputs()/fwrite() instead of fread().

Determining where the file pointer is

To wrap up today's conversation, let's take a look at one more function which will tell you where exactly within a file the file pointer is. This function is called ftell() and has the following syntax:

ftell($file_reference);

This function returns false on error or the current offset of the file pointer starting from the beginning of the file:

<?php
   $fr = fopen("/path/to/myfile.dat", 'r');
   fseek($fr, rand(1, 1024));
   $offset = ftell($fr);
   echo "We randomly landed on the $offset byte of the file.<BR>";
?>>

More about Files to come!

That's all I have for you today on files, which are an important part of PHP. By now you've learned how to deal with both binary and text files. In coming issues, I'll be discussing file permissions, directories, and more, so come back soon.

John Coggeshall is a a PHP consultant and author who started losing sleep over PHP around five years ago.


Read more PHP Foundations columns.

Return to the PHP DevCenter.


Copyright © 2009 O'Reilly Media, Inc.