2

So I have this extremely simple script:

echo "lalalaal";
ob_start();
var_dump(headers_sent());
echo "heretoo";
$html = ob_get_contents();
ob_end_clean();
echo $html;

And it is being run from the command line with:

php n.php

at all times.

I have two servers:

  • My dev server has PHP 5.3.10-1ubuntu3.9 with Suhosin-Patch (cli)
  • My live server has PHP 5.5.9-1+sury.org~precise+1 (cli)

The output on my dev server is:

lalalaal
bool(false)
heretoo

On my live server:

lalalaal
bool(true)
heretoou

I am showing all errors on both servers, why is my live server returning true? What has changed since 5.3 to cause this?

Edit

With var_dumping the results from headers_sent it just tells me that lalalaal causeed it:

lalalaalbool(true)
string(18) "/home/ubuntu/n.php"
int(4)

int(4) pointing to echo "lalalaal"; since it sits under a PHP tag and then a blank line then a comment.

hakre
  • 193,403
  • 52
  • 435
  • 836
Sammaye
  • 43,242
  • 7
  • 104
  • 146
  • 1
    Shouldn't you move your `ob_start()` call to the top of the script? – Cyclonecode Feb 20 '14 at 19:15
  • @KristerAndersson nope it is fine right where it is – Sammaye Feb 20 '14 at 19:15
  • 'lalalalaal' is output before the header command - which is what's throwing the warning you are getting... – random_user_name Feb 20 '14 at 19:15
  • @cale_b then why does it work fine on 5.3? – Sammaye Feb 20 '14 at 19:16
  • You don't have warnings turned on in your error reporting? Probably not a php version issue, but a error reporting issue... – random_user_name Feb 20 '14 at 19:16
  • @cale_b nope I have `E_ALL & ~ E_DEPRECATED` for error_reporting – Sammaye Feb 20 '14 at 19:16
  • 3
    The question says "ob_start not working". ob_start is working, you just have output before the ob_start. Is there another question you mean to ask? – random_user_name Feb 20 '14 at 19:17
  • @cale_b ob_start is supposed to solve this problem – Sammaye Feb 20 '14 at 19:17
  • 2
    ob_start has to be before the output. You know that. So what's the problem? – random_user_name Feb 20 '14 at 19:18
  • No it is not. I know that's not what the docs say. – Sergiu Paraschiv Feb 20 '14 at 19:18
  • @cale_b check out my edit, you will see the problem – Sammaye Feb 20 '14 at 19:32
  • 2
    Still has nothing to do with ob_start. Has to do with headers sending after output is generated. – random_user_name Feb 21 '14 at 17:25
  • @cale_b I output the vardump boolean before sending headers though, check closer at the edit. Ob_start should stop the output from effecting headers_sent there – Sammaye Feb 21 '14 at 17:28
  • 3
    You echo a value to the browser *before* your ob_start. That is sent to the browser *immediately*. *Then* you send a header, which throws a notice because there's already data sent to the browser. *Then* you call ob_start, which *starts* capturing output from that point forward, but then it is too late, because the header issue already happened. ob_start doesn't look backwards, it only captures output *after* you call it. **BTW** I did NOT downvote. – random_user_name Feb 21 '14 at 21:13
  • @cale_b how does `php n.php` output to browser?? – Sammaye Feb 21 '14 at 21:19
  • @cale_b also how do you explain that this worked on php 5.3? You can see the difference between the boolean false and true – Sammaye Feb 21 '14 at 21:47
  • 1
    Again - the issue has nothing to do with ob_start, yet that's what your question is. Do you want to restructure your question? And, to your point on outputting to browser - fair enough - but where are you sending headers? – random_user_name Feb 21 '14 at 22:07
  • @cale_b if it snot lack of ob_start() working causing sent_headers to return two different values on either versions then what is it? That's the only different, both versions are sending out headers (if) – Sammaye Feb 21 '14 at 22:09
  • @cale_b I mean this isnt about the warning anymore, PHP versions are returning two different values for a function that should be consistent across those versions – Sammaye Feb 21 '14 at 22:13
  • Please fix your title. This has nothing to do with `ob_start()`. – PeeHaa Feb 23 '14 at 23:19
  • @Sammaye - I think this is a good question because it addresses common CLI issues due to changes in 5.4 and later. see my answer. – JSON Feb 23 '14 at 23:21
  • php.net shows for the signature on `headers_sent ([ string &$file [, int &$line ]]` - can you check what's in $file and $line? Maybe that could give a hint. – Briareos386 Feb 25 '14 at 17:59
  • @GeneSys sure I'll do that in a bit and edit thanks – Sammaye Feb 25 '14 at 18:00
  • @GeneSys edited, quite predictable result – Sammaye Feb 25 '14 at 22:11
  • @cale_b I do wonder about your understanding of the docmentation since the English is a little vague here: http://uk1.php.net/ob_start `While output buffering is active no output is sent from the script (other than headers),` so what happens to headers? Does ob omit them like it does in 5.3 or does it send them? – Sammaye Feb 28 '14 at 08:03
  • @cale_b I mean I see this comment here: http://uk1.php.net/ob_start#101082 but I did not witness such behaviour in any PHP version. – Sammaye Feb 28 '14 at 08:05
  • Turn your dev-server's output buffering off by default. – Niko Hujanen Mar 02 '14 at 00:33
  • @NikoHujanen in cli it is already off – Sammaye Mar 02 '14 at 00:51

4 Answers4

9

When using a webserver, PHP will send header information to the browser first thing. PHP's cue to send it's header information is the first time the output buffer is used. Header information is sent the first time something placed into to the output buffer, and there's generally no turning back at that point.

The confusion here is from the fact that you're using the CLI. The CLI didn't use headers related functions prior to PHP 5.4.0 because it was purely a command-line tool - thus it wasn't bound to server specific or browser related behavior. However, the CLI in 5.4.0 and later has a built-in webserver cli-server.

You had different rules regarding headers in CLI mode before 5.4.0 because it wasn't built to handle or acknowledge headers, so headers_sent() would return false no matter what. Thats not the case for 5.4.0 and later, including 5.5.

You will need to follow the normal guidelines regarding headers and the output buffer if you want your CLI script to work as expected in both 5.3 and 5.5.

Mark
  • 3,005
  • 1
  • 21
  • 30
JSON
  • 1,819
  • 20
  • 27
  • 1
    I think this is right. I could throw a huge spanner which that the "problem" I got from a third party library that uses code like this (a PHPThumb variant) actually works in the browser, sending headers multiple times for each image it retrieves as a string (it uses the same code for showing as for getting as a string, it uses ob to buffer it). But I think the inbuilt web server could be creating complications here – Sammaye Feb 24 '14 at 00:15
  • 1
    I'm gonna place the bounty on this answer since this is the only answer that hasn't been "move the ob_start()" and attempts to actually answer the question but I still have not got the bottom of this so this question still stands unanswered really – Sammaye Mar 02 '14 at 11:10
6

you're sending headers ('e') after you already echoed 'lalalaal' to the client.

aelgoa
  • 1,193
  • 1
  • 8
  • 24
  • 6
    maybe your PHP configuration supresses these warnings? check your PHP ini for error reporting options – aelgoa Feb 20 '14 at 19:17
  • 1
    Different configs. Compare php.ini and your web server configs. Maybe output compression and/or buffering is enabled on the dev server. – Sergiu Paraschiv Feb 20 '14 at 19:20
  • @SergiuParaschiv I have compared all configs, they all show all errors – Sammaye Feb 20 '14 at 19:22
  • I wrote "output compression and/or buffering" not error reporting. – Sergiu Paraschiv Feb 20 '14 at 19:24
  • @SergiuParaschiv aha and which config settings would they be? – Sammaye Feb 20 '14 at 19:26
  • @SergiuParaschiv you see the output buffering settings are actually hardcoded to off in cli – Sammaye Feb 20 '14 at 19:28
  • Check out my edit I am sure you will prolly change your answer – Sammaye Feb 20 '14 at 19:35
  • And you're sure you are not running php-cgi instead of php-cli? php-cli should never ever try to send headers. php-cgi should. – Sergiu Paraschiv Feb 20 '14 at 19:36
  • @SergiuParaschiv is there a good way to check that? I run fcgi but I always calling `php n.php` which does go to `/usr/bin/php` – Sammaye Feb 20 '14 at 19:37
  • `php -v` should tell you. That is probably your problem. – Sergiu Paraschiv Feb 20 '14 at 19:38
  • @SergiuParaschiv `PHP 5.5.9-1+sury.org~precise+1 (cli) (built: Feb 13 2014 15:53:53) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies` thats my full -v – Sammaye Feb 20 '14 at 19:38
  • @SergiuParaschiv is there another setting anywhere that could be effecting my output? – Sammaye Feb 20 '14 at 19:40
  • Don't know of any. Try to run a diff on all your configs. It might be a bug, but what you're doing is not really "legal" use, so I don't know if anyone else noticed it. – Sergiu Paraschiv Feb 20 '14 at 19:48
  • @SergiuParaschiv the reason why I came across this is because PHP Thumb uses `ob_start()` along with `header()`'s when getting a raw image string after usage in the library, so in my defense this isn't actually my coding. However it has always worked until now – Sammaye Feb 20 '14 at 19:54
1

Try this

<?php
    ob_start(); /* first line, without empty space */
    echo "lalalaal";

    var_dump(headers_sent());
    echo "heretoo";
    $html = ob_get_contents();
    ob_end_clean();
?>
Darwin
  • 62
  • 2
  • 8
  • That technically doesn't solve it, what if I want `lalalaal` outside the ob_start, what if I want to buffer `heretoo`? I am unsure how this explains or solves my problem – Sammaye Feb 24 '14 at 08:00
  • 1
    Also can I ask why is there a closing tag? – Sammaye Feb 25 '14 at 18:02
-1

ob_start() is used to store the contents that you are gonna display in the user's browser.It is used as a BUFFER storage.

EX 1: Take the following Example:

<?php

echo "hi";
header("As you have already displayed "hi", this info will not be sent.);
?>

EX 2: [A practical use of ob_start]

In the below code, the header function will work since the echo informations will be stored in the buffer memory.

<?php
ob_start();
echo "hi";
echo "Hello"
header("This info will be sent");
ob_end_flush();
?>

NOTE: One precaution though you have to take is, you have to include the ob_start() function in the beginning of the script so that it can store the infos in the memory.[This is where you made the mistake in your script by placing it after the echo.]

Abhinav
  • 8,028
  • 12
  • 48
  • 89
  • Hmm I don't understand, I use ob_start in many places half way through the script. Example in Yii2 there is a wdiget called `Block`. it buffers random pieces of information into other PHP threads, merging them back into the master one for later display. You can use this block widget anywhere you like. Ob_start doesn't have to be at the start of the script – Sammaye Feb 28 '14 at 07:57
  • In fact you will find ob_start works nested and in any part of the page. The problem is that between php 5.3 and 5.5 the headers are sent. – Sammaye Feb 28 '14 at 07:59
  • I think you misunderstood, I meant that ob_start have to be included before you output anything to the browser.Now you can output something even in the middle of your code, so at that time you have to include ob_start before that statement – Abhinav Feb 28 '14 at 13:03
  • No many frameworks use ob_start way after the beginning of output, checkout Yii2 for example – Sammaye Feb 28 '14 at 13:05
  • There is NO way you can send a header after you send an output to the browser,Thats the Concept of headers. Headers are something that are sent before a server serves a page to the client and PHP header() function modifies the default headers to serve your purpose. I am very Sure You are missing some key info in your code Do visit this link: http://stackoverflow.com/questions/8028957/how-to-fix-headers-already-sent-error-in-php – Abhinav Feb 28 '14 at 13:06
  • Okay let me get this one straight for u: The thumb rule is,You can decide from which output you want you want to store in the buffer, yes you can use ob_start after outputting something coz you want some other output to get stored in the buffer,but generally its a good practice to use it in the beginning, thts the reason I mentioned it should come before outputting anything[So ther s no compulsion]....This ends now But, For headers, You definitely cannot send any output to browser before using that function – Abhinav Feb 28 '14 at 13:12
  • You should have seen my original question. The reason why I use headers_sent there is because when I used my original question of showing that on PHP 5.3 you can send headers after output in ob_start() (they are ignored in my tests) everyone placed your answer – Sammaye Feb 28 '14 at 13:25
  • In fact if you can see question edits you can see my original question – Sammaye Feb 28 '14 at 13:27
  • ALso there is no output to browser here, only to console – Sammaye Feb 28 '14 at 13:28
  • Then I think You should Check your PHP.ini file of server which has php5.3,Chances are that the php.ini has output_buffering enabled, thats the reason you are able to send your headers – Abhinav Feb 28 '14 at 13:43
  • Output buffering is hardcoded to off in cli...in both php 5.3 and 5.5 – Sammaye Feb 28 '14 at 13:45
  • Then what you sayin that you can send headers even after sending an output can NEVER EVER OCCUR!!! – Abhinav Feb 28 '14 at 13:50
  • I didn't I said that using header() doesn't throw an error, I actually, from my tests, saw that the headers in ob_start are dropped. – Sammaye Feb 28 '14 at 13:51
  • I realise I did actually say: ` you can send headers after outpuy` I should have made that "you can use header()" after output – Sammaye Feb 28 '14 at 13:55