PHP, JavaScript,  and HTML each have their own idiosyncrasies, but they all lack what I would consider useful features of a more strictly typed language like C or C++.   After years of using C and C++ for micro-controllers and applications, I don’t recall problems with whitespace.  Recently, I’ve been working on the client side of an application for Android phones.  I had just finished adding some authentication code to the server, and testing it in a web browser resulted in:

Warning: Cannot modify header information - headers already sent by (output started at /.../.../.../.../mysite/...glue/...login.php:38) in /.../.../.../.../mysite/...glue/...api.php on line 92

I thought that odd, as I had just tested it on my internal server; the errors occurred only on the production server.  Also, it had previously worked on the production server.  I reasoned that the production server has stricter configuration than the internal one, and dove in to find the problem.

The reason my code modified the header information at all is that it sends data in XML format, and I used:

header("Content-type: text/xml; charset=utf-8");

I had read about some of the pitfalls with any output being sent before the headers, but never realized that something could slip into the code so easily.  Fortunately, the Warning message is very descriptive.  Based on the second part of the message (in … api.php on line 92), I used the wget trick to get an exact copy of what the server put out, and found an unexpected tab character at the beginning of the xml.     I decided to add a ob_clean() right before instantiating an XMLWriter object, adding elements, and echoing the output obtained from outputMemory().    And, the ob_clean worked!  But I didn’t leave it that way.

The first part of the Warning message (output started at …login.php) got to the root of the problem.  I found a tab character after the closing php tag ‘?>’.   And, since it is whitespace, it wasn’t obvious that it was there.  I took out the extra tab and the ob_clean() and it works.    Just to be safe, I might put the ob_clean() back in; sort of a belt and suspenders degree of safety.

Leading me to ask: What tools do you use to check your code?  “lint for php” might be a good search term.