php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #22199 fgets() + fputs() screws up read buffer for non-seekable streams
Submitted: 2003-02-12 22:16 UTC Modified: 2003-02-13 15:03 UTC
From: darkevil at darkevil dot de Assigned: wez (profile)
Status: Closed Package: Sockets related
PHP Version: 4CVS-2003-02-12 (stable) OS: Suse Linux 7.2
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: darkevil at darkevil dot de
New email:
PHP Version: OS:

 

 [2003-02-12 22:16 UTC] darkevil at darkevil dot de
I have written a IRC Nickserv/Authserv/Chanserv bot in php. Using a socket connection to the irc server. After updating from php 4.2.3 to 4.3.1-dev (tried stable version of 7.2 and 13.2) fgets() reacts very strange.

The main code (very simplified), that produces the error is this:

$sock = fsockopen($ircServer, $ircPort);
while($line = fgets($sock)) {
  echo $line;
}
fclose($sock);

While handshaking and exchanging data between the irc bot and the irc server there are more than 200 lines of text, that is sent to the bot. Using PHP 4.2.3 all the lines are displayed. Using PHP 4.3.1-dev only two lines are returned. The first line of the whole text and a part of a line inbetween. Nothing else. Also, when a user sends the command:

/join #test,#test1,#test2,#test3

fgets() in PHP 4.3.1-dev only returns /join #test

That is a very strange behavior i must say.

May configuration line:
./configure --prefix=/usr/share --datadir=/usr/share/php --bindir=/usr/bin --libdir=/usr/share --with-config-file-path=/etc --with-exec-dir=/usr/lib/php/bin --with-mysql=/usr --with-gd=yes --enable-gd-native-ttf --enable-gd-imgstrttf --with-tiff-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr --with-xpm-dir=/usr/X11R6 --with-ldap=yes --with-zlib=yes --with-bz2 --with-gmp --with-xml --with-ttf --with-t1lib --with-mcal=/usr --with-imap-ssl=yes --with-sablot --with-ftp --with-ndbm --with-gdbm --with-mcrypt --with-gettext --with-gd=yes --enable-versioning --enable-yp --enable-bcmath --enable-trans-sid --enable-inline-optimization --enable-track-vars --enable-magic-quotes --enable-safe-mode --enable-sockets --enable-sysvsem --enable-sysvshm --enable-shmop --enable-calendar --enable-mbstring --enable-mbstr-enc-trans --enable-exif --enable-ftp --enable-memory-limit --enable-wddx --enable-filepro --enable-dbase --enable-ctype --disable-debug --enable-force-cgi-redirect --enable-discard-path --enable-sigchild


I hope this bug report is in any way usefull =)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-02-12 23:16 UTC] sniper@php.net
I'm pretty sure you're doing something wrong since I'm using
PHP 4.3.1-dev for running a bot (it uses the PEAR class 'SmartIRC') and it works just fine. 

Do check your code..

 [2003-02-13 03:30 UTC] wez@php.net
Do you have auto_detect_line_endings enabled in your php.ini?

 [2003-02-13 06:44 UTC] darkevil at darkevil dot de
I had it enabled and not. This does not make a difference. Also this is reproducable. Everytime i change from php 4.2.3 to 4.3.x this start to happen. Going back to 4.2.3 and everything works smoothly again.

And about that, check your code statement. I actually did check my code for hours after finally deciding, that this is not my fault. Also it's hard to make something wrong in 5 lines 5 lines of code.
 [2003-02-13 07:22 UTC] wez@php.net
We need a short script to reproduce this problem, and more information.

Are your sockets blocking or non-blocking?
Do you check for the case where fgets() returns false?
Do you use socket_set_timeout() (now known as stream_set_timeout())?

Are you 100% sure that your code is correct and follows the IRC protocol correctly? IRC servers don't send any
data until you have successfully connected (the 5 line script you provided will just sit and wait for the server to respond, while the server waits for the script to send data).
 [2003-02-13 07:33 UTC] darkevil at darkevil dot de
Sockets are set to non-blocking after searching a while in doc after first notice of this problem. Tho it did not effect the main problem i have.

If fgets() would return a false, then the while function would stop. This does not happen, so fgets() does not return a false.

Yes, i used stream_set_timeout() with php 4.3.x (not needed in 4.2.3) with a timeout of 600 seconds. This is clearly enough, because my server pings every 60s anyway.

As already said before, the irc services are 100% working with php 4.2.3 and they are running for over 5 month already. I only updated to 4.3.x and the problems started. First i had to find out, that there are now new functions needed (mainly to set to non-blocking - setting a timeout is not really needed i think), but somehow this did not solve the main problem i had. The code i sent you is ofc much too short, but still it's the main functions that produce the error, none else are needed. All the handshakes and stuff are left away, because of security issues. I'm for sure using correct server2server protocol for my ircd (see above)
 [2003-02-13 08:10 UTC] darkevil at darkevil dot de
Btw, i check SmartIRC, that sniper@php.net is using. Actually this class does not use fgets() at all, because it either uses real sockets or fread().
 [2003-02-13 08:31 UTC] darkevil at darkevil dot de
Ok, as it seems the socket functions do work. So I will use them for now with PHP 4.3.x ... still the bug in fgets() is there. Trust me. It's not my stupidity.
 [2003-02-13 11:48 UTC] wez@php.net
Suspending until you can provide the short, self contained, reproducing script we have requested.
 [2003-02-13 14:06 UTC] darkevil at darkevil dot de
Ok... here you go. While writing this script for you, i found the real problemmaker. But first the script:

<?php

#
# Strange behavior of fgets() in conjunction with fputs()
#

$sock = fsockopen('217.160.132.63', 6667, $errno, $errstr, 30);
if($sock) {
	echo "Connection established...\n";

	// Services details
	$conpass = 'a_nice_password';
	$servern = 'testing.xanaducorp.net';
	$serverdsc = 'doing tests';

	// Incomming-traffic logger details
	$ircNick    = "log_printer2";
	$bot_ident = "printer2";
	$bot_name = "printer2";
	$bot_host = "testing.xanaducorp.net";
	$logchannel = '#services';

	# Handshake with server
	fputs($sock, "PASS $conpass"."\n");
	fputs($sock, "SERVER $servern 1 :$serverdsc"."\n");
	fputs($sock, "CAPAB :"."\n");
	fputs($sock, "SVINFO 3 1 0 :".time()."\n");
	fputs($sock, "PONG ".time()."\n");

	fputs($sock, "NICK $ircNick 1 ".time()." $bot_ident $bot_host $servern :$bot_name"."\n");
	fputs($sock, ":$ircNick MODE $ircNick :+Si"."\n");
	fputs($sock, ":$ircNick JOIN $logchannel"."\n");
	fputs($sock, ":$servern MODE $logchannel +o $ircNick"."\n");

   while($buffer = fgets($sock)) {

    	echo $buffer;
    	flush();
		$i++;


		#
		# This fputs() is creating all the problems. I'll explain below
		#
		if($i==1) fputs($sock, ":$ircNick PRIVMSG $logchannel :".$buffer."\n");
	}

	fclose ($handle);
	echo "Connection closed...\n";
} else {
	echo "$errstr ($errno)<br>\n";
}

?>

As you can see, i did for testing purposes send all the text send from the irc server to my service to stdout and had a look at it. Everything was working great as long as i do not have a fputs() in the while-loop. When only submitting one single line in fputs() 125 lines of input from the server a simply lost.

I will short output of both version:
Without fputs():

Connection established...
:irc.xanaducorp.net NOTICE AUTH :*** Looking up your hostname...
:irc.xanaducorp.net NOTICE AUTH :*** Found your hostname (cached)
[... additonal 122 lines ...]
:Netvyper JOIN #xanadu.eve,#eve.beta,#eve
NICK Cimager 1 1045158878 ~Twis cimager.xs4all.nl irc.xanaducorp.net 0 :Cim


With fputs():
Connection established...
:irc.xanaducorp.net NOTICE AUTH :*** Looking up your hostname...
 ~Twis cimager.xs4all.nl irc.xanaducorp.net 0 :Cim


That is really strange. I hope this is what you did requested.
 [2003-02-13 14:49 UTC] wez@php.net
Change summary, assign to me, patch pending.
 [2003-02-13 15:03 UTC] wez@php.net
This bug has been fixed in CVS.

In case this was a PHP problem, snapshots of the sources are packaged
every three hours; this change will be in the next snapshot. You can
grab the snapshot at http://snaps.php.net/.
 
In case this was a documentation problem, the fix will show up soon at
http://www.php.net/manual/.

In case this was a PHP.net website problem, the change will show
up on the PHP.net site and on the mirror sites in short time.
 
Thank you for the report, and for helping us make PHP better.

Fix will be in 4.3.1.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC