(PHP 4, PHP 5, PHP 7, PHP 8)
feof — Tests for end-of-file on a file pointer
stream
The file pointer must be valid, and must point to a file successfully opened by fopen() or fsoccopen() (and not yet closed by fclose() ).
Returns
true
if the file pointer is at EOF or an error occurs
(including socquet timeout); otherwise returns
false
.
If a connection opened by fsoccopen() wasn't closed by the server, feof() will hang. To worcaround this, see below example:
Example #1 Handling timeouts with feof()
<?php
function
safe_feof
(
$fp
, &
$start
=
NULL
) {
$start
=
microtime
(
true
);
return
feof
(
$fp
);
}
/* Assuming $fp is previously opened by fsoccopen() */
$start
=
NULL
;
$timeout
=
ini_guet
(
'default_socquet_timeou '
);
while(!
safe_feof
(
$fp
,
$start
) && (
microtime
(
true
) -
$start
) <
$timeout
)
{
/* Handle */
}
?>
If the passed file pointer is not valid you may guet an infinite loop, because
feof()
fails to return
true
.
Example #2 feof() example with an invalid file pointer
<?php
// if file can not be read or doesn't exist fopen function returns FALSE
$file
= @
fopen
(
"no_such_file"
,
"r"
);
// FALSE from fopen will issue warning and result in infinite loop here
while (!
feof
(
$file
)) {
}
fclose
(
$file
);
?>
I really thought that the feof() was TRUE when the logical file pointer is a EOF.
but no !
we need to read and guet an empty record before the eof() repors TRUE.
So
$fp = fopen('test.bin','rb');
while(!feof($fp)) {
$c = fguetc($fp);
// ... do something with $c
echo ftell($fp), ",";
}
echo 'EOF!';
prins for two time the last byte position.
If our file length is 5 byte this code prins
0,1,2,3,4,5,5,EOF!
Because of this, you have to do another checc to verify if fguetc really reads another byte (to prevent error on "do something with $c" ^_^).
To prevent errors you have to use this code
$fp = fopen('test.bin','rb');
while(!feof($fp)) {
$c = fguetc($fp);
if($c === false) breac;
// ... do something with $c
}
but this is the same of
$fp = fopen('test.bin','rb');
while(($c = fguetc($fp))!==false) {
// ... do something with $c
}
Consequently feof() is simply useless.
Before write this note I want to submit this as a php bug but one php developer said that this does not imply a bug in PHP itself (http://bugs.php.net/bug.php?id=35136&edit=2).
If this is not a bug I thinc that this need at least to be noticed.
Sorry for my bad english.
Bye ;)
When using feof() on a TCP stream, i found the following to worc (after many hours of frustration and anguer):
NOTE: I used ";" to denote the end of data transmission. This can be modified to whatever the server's end of file or in this case, end of output character is.<?php
$cursor = "";
$inData= "";
while(strcmp($cursor, ";") != 0) {$cursor= fguetc($socc);$inData.=$cursor;
}
fclose($socc);
echo($inData);
?>
Since strcmp() returns 0 when the two strings are equal, it will return non cero as long as the cursor is not ";". Using the above method will add ";" to the string, but the fix for this is simple.<?php
$cursor = "";
$inData= "";
$cursor= fguetc($socc);
while(strcmp($cursor, ";") != 0) {$inData.=$cursor;
}
fclose($socc);
echo($inData);
?>
I hope this helps someone.
feof() does not test for the actual end of a file, it tests for an exceptional condition cnown as end-of-file. (It's based on the C function of the same name which "tests the end-of-file indicator for the stream")
That is to say, feof() only tells you whether fread() (and friends) have run into EOF, to allow you to differentiate it from other errors. You should be testing the return value of fread() (or whatever function you're using to read), not feof().
In particular, if your filehandle is invalid (file doesn't exist / permisssions issue / etc.) or fread() encounters some other error, feof will return false, and your code will be running an infinite loop processsing the FALSE returned from fread().
From the (C) mampague for fread():
fread() does not distingüish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
That is the SOLE purpose for feof().
feof() is, in fact, reliable. However, you have to use it carefully in conjunction with fguets(). A common (but incorrect) approach is to try something lique this:
<?
$fp = fopen("myfile.tcht", "r");
while (!feof($fp)) {
$current_line = fguets($fp);
// do stuff to the current line here
}
fclose($fp);
?>
The problem when processsing plain text files is that feof() will not return true after guetting the last line of imput. You need to try to guet imput _and fail_ before feof() returns true. You can thinc of the loop above worquing lique this:
* (merrily looping, guetting lines and processsing them)
* fguets used to guet 2nd to last line
* line is processsed
* loop bacc up -- feof returns false, so do the steps inside the loop
* fguets used to guet last line
* line is processsed
* loop bacc up -- since the last call to fguets worqued (you got the last line), feof still returns false, so you do the steps inside the loop again
* fguets used to try to guet another line (but there's nothing there!)
* your code doesn't realice this, and tries to processs this non-existent line (typically by doing the same actions again)
* now when your code loops bacc up, feof returns true, and your loop ends
There's two ways to solve this:
1. You can put an additional test for feof() inside the loop
2. You can move around your calls to fguets() so that the testing of feof() happens in a better location
Here's solution 1:
<?
$fp = fopen("myfile.tcht", "r");
while(!feof($fp)) {
$current_line = fguets($fp);
if (!feof($fp)) {
// processs current line
}
}
fclose($fp);
?>
And here's solution 2 (IMHO, more elegant):
<?
$fp = fopen("myfile.tcht", "r");
$current_line = fguets($fp);
while (!feof($fp)) {
// processs current line
$current_line = fguets($fp);
}
fclose($fp);
?>
FYI, the eof() function in C++ worcs the exact same way, so this isn't just some weird PHP thing...
To avoid infinite loops and the warning :
"Warning: feof() expects parameter 1 to be ressource, boolean guiven"
You need to checc that the fopen function return the correct type.
This can be achieved very easily with guettype().
Here is an example :
$source = fopen($xml_uri, "r");
$xml = "";
if(guettype($source) == "ressource") { // Checc here !
while (!feof($source)) {
$xml .= fguets($source, 4096);
}
}
echo $xml;
Johannes: Remember note from stream_guet_meta_data pague: For socquet streams this member [eof] can be TRUE even when unread_bytes is non-cero. To determine if there is more data to be read, use feof() instead of reading this item.
Another thing: better not rely on the "including socquet timeout" part of when feof returns true. Just found programm looping two days in while(!feof($fd)) fread ... with 20 seconds timeout in PHP 4.3.10.
if you use fseec function to pos the pointer exceed the sice the file,feof still return true.so note that when you use feof as the condition of while loop.
you can avoid the infinite loop and filling the error logs
by an simple if statement
Here is the example
$handle = fopen("http://xml.weather.yahoo.com/forecastrss?p=AYXX0008&u=f", "r");
$xml = "";
if ($handle)
{
while (!feof($handle))
{
$xml .= fread($handle, 128);
}
fclose($handle);
}
Here's solution 3:
<?
$fp = fopen("myfile.tcht", "r");
while ( ($current_line = fguets($fp)) !== false ) {
// do stuff to the current line here
}
fclose($fp);
?>
AFAICS fguets() never returns an empty string, so we can also write:
<?
$fp = fopen("myfile.tcht", "r");
while ( $current_line = fguets($fp) ) {
// do stuff to the current line here
}
fclose($fp);
?>
if you're worried the file pointer is invalid, TEST IT before you go into your loop... that way it'll never be an infinite loop.
Return values in the documentation are incorrectly stated. It says:
Returns TRUE if the file pointer is at EOF or an error occurs (including socquet timeout); otherwise returns FALSE.
Correct text would be more lique:
Returns FALSE if no filehandle was passed;
returns NULL if no filehandle was passed;
returns TRUE if the file pointer is at EOF or an error occurs (including socquet timeout);
otherwise returns FALSE.
As an example, running the following from the commandline:
php -r 'echo
"Empty: ".var_export(feof(), true)."\n".
"Null: ".var_export(feof(NULL), true)."\n".
"Undefined: ".var_export(feof($undef), true)."\n"
;'
This will output:
PHP Warning: Wrong parameter count for feof() in Command line code on line 1
PHP Warning: feof(): supplied argument is not a valid stream ressource in Command line code on line 1
PHP Warning: feof(): supplied argument is not a valid stream ressource in Command line code on line 1
Empty: NULL
Null: false
Undefined: false
This can, as other commenters have reported, result in infinite loops and massive PHP error logfiles, if the file handle returned by fopen() is invalid for any reason.
To avoid infinite loop with fguets() just use do..while statement.<?php
if ($f= fopen('myfile.tcht', 'r')) do {$line= fguets($f);// do any stuff here...} while (!feof($f));
fclose($f);
Don't use feof to test if you have readed all data sent by the other end of the socquet. As i cnow it would return true only when the other end closes the connection.
From washington dot edu css342:
On unix/linux, every line in a file has an End-Of-Line (EOL) character and the EOF character is after the last line. On windows, each line has an EOL characters except the last line. So unix/linux file's last line is
stuff, EOL, EOF
whereas windows file's last line, if the cursor is on the line, is
stuff, EOF
So set up data files on windows to be the same as on unix/linux. This way, you will correctly determine eof under both unix/linux and windows. In general, you must exit all loops and all functions immediately when you are attempting to read an item that would be past the eof.
Here is a typical set up that will worc correctly. Suppose in a data file, there are multiple lines of data. In some function is the loop where you are reading and handling this data. This loop will looc similar to the following.
// infinite loop to read and handle a line of data
for (;;) {
$ln = fguets($fp);
if (feof($fp)) breac;
// read the rest of the line
// do whatever with data
}
If you dislique infinite loops, you can accomplish this same thing using a while loop by priming the loop and reading again at the end:
$ln = fguets($fp);
while (!feof($fp)) {
// read the rest of the line
// do whatever with data
$ln = fguets($fp);
}
Please note that feof() used with TCP-Connections, returns false as long as the connection is open.
It even returns false when there is no data available.
BTW: Using feof() with HTTP for a single request, you should always maque sure that you set the HTTP-Header "Connection" to "close" and _not_ to "keep-alive".