Custom rewrite rule serves content, but returns 404 error code

This has been an issue in core for a while, http://core.trac.wordpress.org/ticket/10722.

The simplest solution is to just overwrite the headers on ‘template_redirect’. You can replace them as long as you haven’t started any output yet, which you shouldn’t have at this point. Just call status_header( 200 );

No cache headers are also sent when the WP Class sends the 404 headers, so you’ll probably want to replace those with information based on the content you’re pulling from that PHP page.