note 36191 added to function.fgets
| From: | jbayman at hobbithell dot com | Date: | Tue, 30 Sep 2003 06:29:20 +0000 |
| Subject: | note 36191 added to function.fgets | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-57374@lists.php.net to get a copy of this message | ||
According to the documentation, fgets will return either a string or FALSE on error... However,
this is NOT true and applies for almost all stream functions (list of known functions affected at
bottom of post). The problem is, when a PHP function opens a stream, it uses
"php_stream_from_zval" call to open it. This is a macro for
"ZEND_FETCH_RESOURCE2" which in turn is another macro which calls
"zend_fetch_resource" and then checks the return code using the macro
"ZEND_VERIFY_RESOURCE" which will call "RETURN_NULL();" if
"zend_fetch_resource" failed. In C/C++ (which it is coded in C) a macro is a piece of
code which is inserted where the macro is called at compile time. What that means is, it
effectively changes the definition of fgets to include this code which will cause fgets to return
NULL if the resource cannot be opened.
Long story short, ANY function (list of known functions affected at bottom of post) calling on
"ZEND_FETCH_RESOURCE" or "ZEND_FETCH_RESOURCE2" (and possibly others as well)
WILL return NULL if it is unable to open the resource. This includes basically ALL of the stream
functions as possibly others. So this post applies to a LOT of functions in which the documentation
fails to inform you that it may return NULL if the resource was unable to be opened. (Note: a
resource here is referring to it's HANDLE. As such, it means that only functions requiring a
resource handle are affected by this, not functions like fopen which return a resource handle)
This mainly happens when you open a resource and fail to check to make sure it returns a valid
handle to the resource.
So in short, make sure you check your results from functions such as fgets for both FALSE as well as
NULL. To demonstrate:
// fsockopen returns int on success and bool(FALSE) on failure
$fp = fsockopen("127.0.0.1", 110);
if(is_bool($fp))
{
// fsockopen failed
exit();
}
// fgets returns string on success, bool(FALSE) on failure,
// and NULL if an invalid resource handle was supplied
// Note: This will cause an error to be outputted if you
// have displaying errors enabled under PHP
$result = fgets($fp);
if(is_bool($fp) || is_null($fp))
{
// fgets failed - fsockopen probably returned FALSE
// and you didn't verify that... SHAME on you!
fclose($fp);
exit();
}
While this could technically be considered a bug, it is actually not significant, not to mention can
be easily avoided by asserting that you pass it a valid resource handle. It seems it's more of
a documentation error, however... If the functions were to use
"php_stream_from_zval_no_verify" and test "xstr" (argument 1 of
php_stream_from_zval_no_verify) and return FALSE instead of NULL on that error, then the current
documentation would be correct... Question is, is it really a bug or was it the intention of the
programmer? After careful examination of all code, it would appear to be more of the intention
rather then a bug.
This is true for all releases of PHP up to September 30th, 2003, including PHP Version 5.0.0b1
"ZEND_VERIFY_RESOURCE" and "ZEND_FETCH_RESOURCE2" are defined in
"Zend/zend_list.h"
"php_stream_from_zval" is defined in "main/php_streams.h"
"fgets" (the PHP function) is defined in "ext/standard/file.c"
Note: Not ONE of these functions documents this behaviour
and probably should... Even if it is a bug because all
current and prior version are subject to this
List of known functions affected:
flock
fclose
pclose
feof
fgets
fgetc
fgetss
fwrite
fflush
rewind
ftell
fseek
fpassthru
ftruncate
fstat
fread
fgetcsv
and any alias of named commands like "fputs" which is an alias for "fwrite"
----
Manual Page -- http://www.php.net/manual/en/function.fgets.php
Edit Note -- http://master.php.net/manage/user-notes.php?action=edit+36191
Delete Note -- http://master.php.net/manage/user-notes.php?action=delete+36191&report=yes
Reject Note -- http://master.php.net/manage/user-notes.php?action=reject+36191&report=yes