Edit report at http://bugs.php.net/bug.php?id=51056&edit=1
ID: 51056 Updated by: lbarn...@php.net Reported by: magical...@php.net Summary: fread() on blocking stream will block even if data is available Status: Feedback -Type: Bug +Type: Documentation Problem Package: Streams related Operating System: Linux Gentoo 2.6.32 PHP Version: 5.3.1 New Comment: > I still believe fread() should not hang when it has data it can return. It follows fread() behavior since years and I believe it should not change. > The C counterpart doesn't C's fread() does :) > and the manual says it doesn't. The manual looks wrong on this point, "reading will stop after a packet is available" is never true, whatever packet means. fread() (both PHP's and C's) returns less data than asked only on EOF or errors. The only reliable way of doing non-blocking i/o is still to use non-blocking streams ;-) Previous Comments: ------------------------------------------------------------------------ [2010-03-11 21:39:48] magical...@php.net I still believe fread() should not hang when it has data it can return. The C counterpart doesn't, and the manual says it doesn't. Regarding test 51056-2.phpt.txt the manual explicitly says that this *can happen* on anything else than files (read warning in example #3 on http://php.net/fread ) While I understand your concern for people who might be relying on current bogus behaviour I find this very unlikely considering network streams are subject to lags and different kinds of behaviour due to the large amount of tcp implementations on internet. In the worst case, the manual explicitly warns against relying on fread() returning as many bytes as requested, and says buffering must be used. ------------------------------------------------------------------------ [2010-03-11 21:23:43] lbarn...@php.net > Apache [...] uses timeouts [...] to detect dead clients This is what I was meaning :) (and I though you was meaning this too : "application handling data from network should handle cases when received data is not complete") Dead clients, or situations like this are not the "normal case", and sometimes this can be handled with timeouts. If you are in situations where this is the normal case, one solution is to use non blocking streams. The following code does exactly what you are asking for (if there is something to read, return it; else, block) : stream_set_blocking(..., 0); while (stream_select(...)) { $data = fread(...); } If it does not works with SSL streams, then SSL stuff should be fixed instead. ------------------------------------------------------------------------ [2010-03-11 20:26:59] magical...@php.net > This will block anyway when the buffer is empty and you won't be able to known when it is empty, so you can't rely on this (sometimes it will block, sometimes not). PHP always calls poll() before read, so it knows if there is nothing to read. stream_select() will return the socket as "ready" if there is data pending in php buffer (even if there's no data on the socket), just so we can read it. > Also, some applications may rely on the blocking and will break if it is changed. This behavior exists since at least PHP 5.1. fread() manual explicitly warns about this: When reading from anything that is not a regular local file, such as streams returned when reading remote files or from popen() and fsockopen(), reading will stop after a packet is available. This means that you should collect the data together in chunks as shown in the examples below. On the contrary, using blocking streams together with stream_select() may lead to async program blocking because stream_select() saw there was pending data, but a new packet will not arrive anytime soon. > As this is not the normal case I would suggest to introduce some timeout handling (this is what applications like e.g. Apache does, I guess), or fixing what prevents you from using non blocking i/o with SSL streams instead. It is the normal case to receive less than expected data as documented on the php manual. Apache (or any correctly coded networking app) does not uses timeouts (except to detect dead clients), instead it uses read() which is reliable (ie. not hang when there is data that can be returned). By the way I have looked at what causes the problem I have with SSL streams, and it could be worked around by switching the streamd between blocking mode and non-blocking mode depending on the situation, however I would prefer to avoid that (and it doesn't change the fact that fread() does not comply with what is expected from it, both from read() syscall behaviour and php's manual) ------------------------------------------------------------------------ [2010-03-11 16:51:20] lbarn...@php.net > When data is already available in buffer, an information should be passed to the lower-level read() to let it know it should not block. This will block anyway when the buffer is empty and you won't be able to known when it is empty, so you can't rely on this (sometimes it will block, sometimes not). Also, some applications may rely on the blocking and will break if it is changed. This behavior exists since at least PHP 5.1. > Considering any application handling data from network should handle cases when received data is not complete As this is not the normal case I would suggest to introduce some timeout handling (this is what applications like e.g. Apache does, I guess), or fixing what prevents you from using non blocking i/o with SSL streams instead. ------------------------------------------------------------------------ [2010-03-11 02:21:59] magical...@php.net Hi, I know about fread() returning less data than asked for, however I could not modify this behaviour without passing some kind of value to lower-level read operation, which will call poll() if socket is blocking. When data is already available in buffer, an information should be passed to the lower-level read() to let it know it should not block. The only non-intrusive solution to fix this would be to temporarly pass socket in non-blocking mode if data was found in PHP buffer. Considering any application handling data from network should handle cases when received data is not complete, I believe it was best to return immediatly if data is found and let the application call fread() again rather than trying to workaround this problem with a dirty solution like passing temporarly in non- blocking mode. Another solution would be to add an argument to the internal read call ("do not block") however it would change the API for the internal stream api, and would require the argument to be handled into each stream wrapper. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/bug.php?id=51056 -- Edit this bug report at http://bugs.php.net/bug.php?id=51056&edit=1