tags:

views:

68

answers:

4

I come from a C and C++ background but also play with some web stuff. All us C folks (hopefully) know that calling feof on a FILE* before doing a read is an error. This is something that stings newbies to C and C++ very often. Is this also the case for PHP's implementation?

I figure it has to be because the file could be a socket or anything else where it is impossible to know the size before finishing reading. But just about every PHP example (even those found on php.net I've seen looks something like this (and alarms go off in my head):

$f = fopen("whatever.txt", "rb");
while(!feof($f)) {
    echo fgets($f);
}
fclose($f);

I know it is preferable to write this like this and avoid this issue:

$f = fopen("whatever.txt", "rb");
while($line = fgets($f)) {
    echo $line;
}
fclose($f);

but that's besides the point. I tried testing if things would fail if I did it "the wrong way", but I could not get it to cause incorrect behavior. This isn't exactly scientific, but I figured it was worth a try.

So, is it incorrect to call feof before an fread in PHP?

There are a couple of ways that PHP could have done this differently that C's version, but I feel they have downsides.

  • they could have it default to !EOF. This is sub-optimal because it may be incorrect for some corner cases.

  • they could get the file size during an fopen call, but this couldn't work on all types of file resources, yielding inconsistent behavior and would be slower.

A: 

At least I never head problems using feof without making a read before it. And as php.net doesn't warn about possible errors with this usage, it should be considered safe.

Okay, it warns about invalid file pointers and hanging streams, but these wouldn't be resolved by first reading either, would they?

nikic
+3  A: 

PHP doesn't know whether it's at the end of the file until you've tried to read from it. Try this simple example:

<?php 
$fp = fopen("/dev/null","rb"); 
while (!feof($fp)) { 
    $data = fread($fp, 1);
    echo "read " . strlen($data) . " bytes";  
} 
fclose($fp); 
?>

You will get one line reading read 0 bytes. feof() returned true even though you were technically at the end of the file. Usually this doesn't cause a problem because fread($fp, 1) returns no data, and whatever processing you're doing on that handles no data just fine. If you really do need to know if you're at the end of the file, you do have to do a read first.

MightyE
A: 

Your assertion about not calling feof before an fread is not correct - consequently the question is not valid.

Anonymous
Did you create your account just to give us this valuable contribution?
anon
@Anonymous: in C it is most certainly a logical error to call `feof` before an operation that can set the EOF flag. `fopen` is not one of those operations.
Evan Teran
Arrrggghhh! It is most certainly not an error, logical, syntactical, or otherwise. It is perfectly valid. If you understand what it does - it will behave exactly as expected, as MightyE above explained. The question framed the condition as an error; it is not.
Anonymous
A: 

Hi All,

This may be more of a question than an answer, but why not use file_get_contents()? In my experience, if you are reading a file or a stream, this function does the dirty work for you (assuming you want to read the entire resource to a string, or know/can compute a limit and offset). Its sister function file_put_contents() works well, in reverse.

For instance, here's an example:

$expected_content = "Hello Stack Overflow!"
$real_content = file_get_contents("/path/to/file.txt");
if ($expected_content != $real_content){
   file_put_contents("/path/to/file.txt", $real_content);
}

or a stream:

$expected_content = "Hello Stack Overflow!"
$real_content = file_get_contents("http://host.domain.com/file.txt");
if ($expected_content != $real_content){
   $options = array('ftp' => array('overwrite' => true));
   $stream = stream_context_create($options); 
   file_put_contents("ftp://user:[email protected]/file.txt", $real_content, 0, $stream);
}

Then you don't need to worry about EOF or anything, it does it for you (ftp put gets a bit dicey, but that's ok). Of course, this won't work in all situations...

Is there something that I'm missing from the original question that makes this approach unfeasible?

Tim
@Tim: Your approach is fine and completely reasonable, my question is more academic than practical. I just wanted to know if `foef` in PHP has the same behavior as in C. Thanks.
Evan Teran
Ah, an academic, I didn't see your leather jacket with tweed elbows 8o)(Homer Simpson FTW, "CORRECTION, I ruined two jackets!")
Tim