I have a function that should return JSON responses to the client and then carry on processing without locking up the client, this seems to work fine unless I add the Content-Length header (which I'd like to do to ensure the client is freed up). The function is:
function replyAndCarryOn($responseText){
ignore_user_abort(true);//stop apache killing php
ob_start();//start buffer output
echo $responseText;
session_write_close();//close session file on server side to avoid blocking other requests
header("Content-Encoding: none");
header('Content-Type: application/json; charset=utf-8');
header("Content-Length: ".ob_get_length());
header("Connection: close");
ob_end_flush();
flush();
}
This works fine except the JSON string returned to the browser is truncated, due to the Content-Length being wrong. For example the following string
{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1}, "uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"Payment"}
will turn up as:
{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1},{"uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"
I could just leave the Content-Length header out and apache (2.2) will automatically add the 'Transfer-Encoding:"chunked"' header which seems to work, but I'd like to get to the bottom of why ob_get_length doesn't return the value I need, I understand it can produce results that are too long if gzip is enabled but I'm seeing the opposite where the value is too short.
So I'd like to know:
a) what am I doing wrong in getting the content length?
b) is there any issue leaving it out?
Following the comment by @Xyv it seems the server outputs a new line and eight spaces before the output string, however this is not included in the ob_get_length return. Embarrassingly it turns out it was a carriage return and eight spaces somehow added before the first php tag.
I thought I'd post this as answer for better readability.
Maybe first capture the output, then make the headers, and then the body?
For me this example works:
<?php
function replyAndCarryOn($responseText){
ignore_user_abort(true);//stop apache killing php
ob_flush( );
ob_start( );//start buffer output
echo $responseText;
session_write_close();//close session file on server side to avoid blocking other requests
header("Content-Encoding: none");
header('Content-Type: application/json; charset=utf-8');
header("Content-Length: ".ob_get_length());
header("Connection: close");
echo ob_get_flush();
flush();
}
replyAndCarryOn( '{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1}, "uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"Payment"}' );
?>
Update Important to know would be that ob_start()
should come before outputting any body. The buffers will miss this data, and there fore it will probably not be counted. I am not an expert with output buffering, but ensure to place ob_start
in the beginning of your script, this way it will be hard(er) to make any mistakes. (So be carefull placing spaces and/or Tabs before your initial <?php
).