Reading from Files
PHP provides a number of functions for reading data from files. These enable you to read by the byte, the line, or even the character.
Reading Lines from a File with fgets() and feof()
After you have opened a file for reading, you will often need to access it line by line. To read a line from an open file, you can use fgets(), which requires the file resource returned from fopen() as an argument. You must also pass it an integer as a second argument. This specifies the number of bytes the function should read if it doesn't first encounter a line end or the end of the file. The fgets() function reads the file until it reaches a newline character ("\n"), the number of bytes specified in the length argument, or the end of the file.
$line = fgets( $fp, 1024 ); // where $fp is the file resource returned by fopen()
Although you can read lines with fgets(), you need some way of telling when you have reached the end of the file. The feof() function does this, returning true when the end of the file has been reached and false otherwise. Once again this function requires a file resource as its argument:
feof( $fp ); // where $fp is the file resource returned by fopen()
You now have enough information to read a file line by line, as shown in Listing 10.9.
Listing 10.9 Opening and Reading a File Line by Line
1: <html> 2: <head> 3: <title>Listing 10.9 Opening and reading a file line by line</title> 4: </head> 5: <body> 6: <?php 7: $filename = "test.txt"; 8: $fp = fopen( $filename, "r" ) or die("Couldn't open $filename"); 9: while ( ! feof( $fp ) ) { 10: $line = fgets( $fp, 1024 ); 11: print "$line<br>"; 12: } 13: ?> 14: </body> 15: </html>
We call fopen() on line 8 with the name of the file that we want to read, using the or operator to ensure that script execution ends if the file cannot be read. This usually occurs if the file does not exist, or (on a Unix system) if the file's permissions won't allow the script read access to the file. The actual reading takes place in the while statement on line 9. The while statement's test expression calls feof() for each iteration, ending the loop when it returns true. In other words, the loop continues until the end of the file is reached. Within the code block, we use fgets() on line 10 to extract a line (or 1024 bytes) of the file. We assign the result to $line and then print it to the browser on line 11, appending a <BR> tag for the sake of readability.
Reading Arbitrary Amounts of Data from a File with fread()
Rather than reading text by the line, you can choose to read a file in arbitrarily defined chunks. The fread() function accepts a file resource as an argument, as well as the number of bytes you want to read. It returns the amount of data you have requested unless the end of the file is reached first.
$chunk = fread( $fp, 16 );
Listing 10.10 amends our previous example so that it reads data in chunks of 16 bytes rather than by the line.
Listing 10.10 Reading a File with fread()
1: <html> 2: <head> 3: <title>Listing 10.10 Reading a file with fread()</title> 4: </head> 5: <body> 6: <?php 7: $filename = "test.txt"; 8: $fp = fopen( $filename, "r" ) or die("Couldn't open $filename"); 9: while ( ! feof( $fp ) ) { 10: $chunk = fread( $fp, 16 ); 11: print "$chunk<br>"; 12: } 13: ?> 14: </body> 15: </html>
Although fread() allows you to define the amount of data acquired from a file, it won't let you decide the position from which the acquisition begins. You can set this manually with the fseek() function. fseek() enables you to change your current position within a file. It requires a file resource and an integer representing the offset from the start of the file (in bytes) to which you want to jump:
fseek( $fp, 64 );
Listing 10.11 uses fseek() and fread() to output the second half of a file to the browser.
Listing 10.11 Moving Around a File with fseek()
1: <html> 2: <head> 3: <title>Listing 10.11 Moving around a file with fseek()</title> 4: </head> 5: <body> 6: <?php 7: $filename = "test.txt"; 8: $fp = fopen( $filename, "r" ) or die("Couldn't open $filename"); 9: $fsize = filesize($filename); 10: $halfway = (int)( $fsize / 2 ); 11: print "Halfway point: $halfway <BR>\n"; 12: fseek( $fp, $halfway ); 13: $chunk = fread( $fp, ($fsize - $halfway) ); 14: print $chunk; 15: ?> 16: </body> 17: </html>
We calculate the halfway point of our file by dividing the return value of filesize() by 2 on line 10. We can then use this as the second argument to fseek() on line 12, jumping to the halfway point. Finally, we call fread() on line 13 to extract the second half of the file, printing the result to the browser.
Reading Characters from a File with fgetc()
fgetc() is similar to fgets() except that it returns only a single character from a file every time it is called. Because a character is always 1 byte in size, fgetc() doesn't require a length argument. You simply need to pass it a file resource:
$char = fgetc( $fp );
Listing 10.12 creates a loop that reads the file "test.txt" a character at a time, outputting each character to the browser on its own line.
Listing 10.12 Moving Around a File with fseek()
1: <html> 2: <head> 3: <title>Listing 10.12</title> 4: </head> 5: <body> 6: <?php 7: $filename = "test.txt"; 8: $fp = fopen( $filename, "r" ) or die("Couldn't open $filename"); 9: while ( ! feof( $fp ) ) { 10: $char = fgetc( $fp ); 11: print "$char<BR>"; 12: } 13: ?> 14: </body> 15: </html>