Fixing Feed Problems with WordPress 2.0.6 and PHP 5.2

Upgraded to WordPress 2.0.6 and now feeds are broken. At least, they’re broken in Firefox, IE7, and KDE (Konqueror & Akregator). Something seems to be interrupting the transfer, causing them to get a blank file. Oddly, they work fine in Opera, the LWP “GET” command-line utility, and Dillo (not that Dillo can do anything but display the source, but it gets the whole file.) Even more oddly, SeaMonkey seems to have no problems. You’d think Firefox and SeaMonkey would have the same issues. Also, I seem to be able to sometimes get it to work on reload.

Anyway, I’m working on it. If you read this site via RSS or Atom, and it is working, let me know (and let me know which feed reader you’re using). I suppose it could be cookie-related, though I’ve already tried clearing cookies. I’ve also tried disabling just about every plugin I use that does something to feeds or headers, to no avail.

Update: I think I’ve got it. By using the Tamper Data extension, I was able to determine that the 304 Not Modified status was not being set properly. Instead of actually issuing the 304 status, it would issue a 200 OK, then send a Status: 304 header later in the response. It never showed any problems on command-line GET or HEAD because they weren’t conditional. That’s also why forcing reload would work.

I looked into wp-includes/functions.php and found the status_header function. Then I looked at the following line:

@header("Status: $header $text");

In theory this should work. Traditionally, setting a “Status” header will replace the actual HTTP status. But that’s not how the PHP manual says to do it. They suggest issuing the actual header that the server would send: HTTP/1.1 304 Not Modified. I noticed that the header function in PHP has some optional parameters, including one to force the HTTP status. That felt a little cleaner than hard-coding the protocol (since an older browser might make an HTTP/1.0 request, and it should get an HTTP/1.0 response), so I changed the line to this:

@header("Status: $header $text", TRUE, $header);

It seems to have fixed the problem.

For the record, this is PHP 5.2.0 on Apache 1.3.37 using the mod_php interface.

Update 2: Simpler fix just removes the if.. statement and else… section so that it’s just the following:

@header("HTTP/1.1 $header $text");

Bug reported as Ticket 3528.

It’s also worth mentioning that I had to apply the workaround in Ticket 3354 for another issue (single-post pages were getting cut off before the comments).

Update 3: Here are the exact changes I made:

Keep in mind that this has only been tested on this config. If feeds still work after you upgrade, don’t change it.

Open the file wp-includes/functions.php and look for this section:

function status_header( $header ) {								
	if ( 200 == $header )
		$text = 'OK';
	elseif ( 301 == $header )
		$text = 'Moved Permanently';
	elseif ( 302 == $header )
		$text = 'Moved Temporarily';
	elseif ( 304 == $header )
		$text = 'Not Modified';
	elseif ( 404 == $header )
		$text = 'Not Found';
	elseif ( 410 == $header )
		$text = 'Gone';

		if ( substr(php_sapi_name(), 0, 3) == 'cgi' )
			@header("HTTP/1.1 $header $text");
		else
			@header("Status: $header $text");
}

In the last four lines (not counting the closing }), disable everything but the one with HTTP/1.1 by adding // to the beginning.

		//if ( substr(php_sapi_name(), 0, 3) == 'cgi' )
			@header("HTTP/1.1 $header $text");
		//else
			//@header("Status: $header $text");

Update 4: Mark Jaquith has posted more on this issue, including a patch and a replacement functions.php.

View Kelson Vibber's LinkedIn profileView Kelson Vibber's profile on LinkedIn