How to use ob_* to set the content length in the header? - php

I am trying to create a webservice in Yii. The web service is working fine but what i am concerned about is how to use ob_start() group all together so that i could set the Content-length in the header. I read a lot about ob_* group but still i am very much confused about it.
Suppose this is the web service
public function giveTimestamp()
{
$query='select current_timestamp( );';
$record= Yii::app()->db->createCommand($query)->queryScalar();
return $record;
}
Now what I am trying to do is that I will set the content length of the header while sending this data. Now the at client side user will check if he has received the data of the told length. if not then he will send the request again otherwise there will be no request.
SO how can i use this ob_* in combination.?

To get output size in header, you need to have access to output block:
ob_start(); // enable buffering
echo 'content'; // do the output to memory
header('Content-Length: ' . ob_get_length()); // send header
ob_end_flush(); // send content of buffer and terminate it
However, I can not help you with Yii part, as I do not have experience of work with it.

There are two Yii ways of doing this.
Use afterRender to add the header. This will affect every action in a controller unless you work around that, so use cautiously. http://www.yiiframework.com/doc/api/1.1/CController#afterAction-detail
Use a custom filter and apply it as needed to all actions or select actions. I would probably go this route, as you have more flexibility in the future. Another choice is whether to use an inline filter (much like afterRender above or a class-based filter). Class-based makes it easier to apply your filter across controllers. http://www.yiiframework.com/doc/guide/1.1/en/basics.controller#filter

Related

Server-sent events in PHP (without echo or print)

We have built a prototype application in PHP and JS using Server-Sent Events (single AJAX requests, multiple streamed events sent by event handlers in PHP). Essentially the PHP at some point is using echo to send data back, much like this example: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#sending_events_from_the_server i.e.
echo "event: ping\n";
However the platform we are building for (Magento) has strict coding standards that prohibit echo and print (and print_r and var_dump). Is there any way around this aside from scrapping SSE and setting up AJAX polling?
Well, I think you have 2 ways of "echoing" something in Magento.
1. Adding your PHP file to /pub
Yes, you can run you custom PHP file to "echo" whatever you want.
But you will need to place it under <magento folder>/pub/yourfile.php.
If you're using nginx you will also need to create an exception for your file. Otherwise, Magento's routing will be used.
For doing that, find something like location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check)\.php$ { in your nginx file, and add yourfile.php there.
For example:
location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check|yourfile)\.php$ {.
Once your file is there, it will be served under yourstore.com/yourfile.php or yourstore.com/pub/yourfile.php (in case you are wrongfully exposing the root directory).
2. The magento way - create a controller
You will need to create a module and a controller.
There are plenty of tutorials out there explaining how to create them.
Here you can find how to create the basic module's structure.
And in this other article you can see how to create different controllers with different types of return.
Magento does have strict standards as part of there PHPCS configuration that need to be adhered to before they will allow you publish a module to there market, there is not Solid fix for the issue you have mentioned regarding using echo or print in a magneto file as part of your module. however we have found a work around by leveraging phps Output Buffering.
We have successfully submitted a module using the below mentioned function and example.
You can use ob_start() and ob_end_flush() it behaves similar to how a print or echo would when interacting with the event stream. See link below for example.
Why?
The ob_flush() function outputs the contents of the topmost output buffer and then clears the buffer of the contents. The output may be caught by another output buffer or, if there are no other output buffers, sent directly to the browser ( IE. your currently open stream ).
Example:
/**
* Send Data
*
* #param string $content
*/
function sseEchoAlternative(string $content)
{
ob_start(function () use ($content) { //Expect a warning here
return $content;
});
ob_end_flush();
}
Ref: ServerSentEvents.php

Symfony 2.7 set header from StreamedResponse's callback

I have to set dynamically my Content-Type into the StreamedResponse's callback.
I wrote a code like this that it works fine on Symfony 2.3 but not on 2.7. The returned Content-Type is text/html.
function indexAction()
{
$r = new \Symfony\Component\HttpFoundation\StreamedResponse();
$r->setCallback(function() use ( & $r)
{
// ...
$r->headers->set('Content-Type', 'application/json');
// ...
});
return $r;
}
I found this commit that it can be on but i don't really understand...
https://github.com/symfony/http-foundation/commit/6a0838a26d54eff153b825e1550c1f6fa05a0941
It looks like we can now only set header outside the callback.
It works if i send headers with the native php function into the closure but it's dirty...
header('Content-Type: application/json');
if someone has a clue...
Thanks!
Streamed response made for purposes when you need long-polling connections. And so you have to know what content-type it will serve before you send any data.
When you return your Response object in action Symfony already sends headers and starts to stream output from callback function. In this moment it is not right to send another header.
P.S. I have never seen case when you really need StreamedResponse and need to set Content-Type dynamically.
To be accurate, you can use hack with replacing headers up to version 2.7.19, it was merged in 2.7.20
As #MichaelSivolobov said in his answer, I also have never seen cases when you need it
I'm sure such commits are always made for enforce better application design. When I see such cases as in your example, it's a some kind of red flag to rethink code/data flow

Is there a need for die; after print json_encode() when responding to api calls?

I'm creating various 'my version' of web services. Basically, it's a yii controller with lots of actions.. each action is as follow
public function actionNameOfWebService()
{
if(isset($_POST))
{
// do some processing, when I have a result... I do ..
print CJSON::encode('result.');
}
else
{
print CJSON::encode('only post methods allowed');
}
}
Lots of those actions are in one particular controller. Everything's working fine..before I go to production, do I need to add a 'die;' statement after every print CJSON::encode statement.
Since you are using Yii, you should simply use :
Yii::app()->end();
http://www.yiiframework.com/doc/api/1.1/CApplication#end-detail
No. You don't absolutely need die or exit. I would argue that using it is a bit of anti-pattern. It breaks encapsulation.
If you have some kind of output buffering set up the die might actually be bad. If you're proxying a request die will kill the whole process etc. There are more scenarios like this.
You definitely should use Yii::app()->end();This is because if you have any debugging output, or profiling output, this will also be included in the response unless you tell the app to finish. Your validation could break if you fail to include this.
You don't have to but when you add it, you'll be sure that nothing will be printed after JSON, which will break parsers attempts to read that data.
But if you know that there is nothing more, you can skip it.

Suppress echo from PHP include file

I have a file PHP01.php which:
- performs a function
- creates an array
- echo's some message
I need to include this file in another php script, say PHP02.php as I need access to the array it created. But when I jquery POST request to PHP02.php, the data it returns also has the echo from PHP01.php
How can I suppress the echo from the first file?
You can output buffer it if editing or otherwise restructuring is not possible:
ob_start();
include "PHP02.php";
ob_end_clean();
If you can, you should look at refactoring the code in the original PHP file. If it's performing a function, it should do that. Then, the code that called the function should decide if they want to echo a message.
As you've just learned, this is an important part of orthogonal design. I'd recommend re-writing it so that it performs what you want it to, and let the code that calls the function, decide what they want to output. That way you won't have to worry about these things again.
You can also look into using output buffers. See ob_flush in PHP: http://php.net/manual/en/function.ob-flush.php
Try adding a conditional to PHP01.php that checks to see where it is being called from, this will ensure that you only echo it out if the file making the call is PHP01.php
Additionally it is better if you place functions in their own file to be included if needed so as to keep certain features that are present from being included for example in PHP01.php you can add include 'function01.php'; and it will have that function shared across the two files.
create a new function without the echo

Can PHP detect the status code that it has or is preparing to send to the browser?

I am sending a status code via the header function, such as header('HTTP/1.1 403');, and would like to in another area of my code detect what status code is to be sent (in particular if I have sent an error code of some nature). As has been mentioned elsewhere, headers_list() does not return this particular item, and it's unclear to me if it actually counts as a header, as neither Firebug nor Fiddler2 treat it with the headers. So - how can a PHP script detect which status code is about to be sent to the browser?
I would rather not use a wrapper function (or object) around the header method, or otherwise set some global variable along with the sending of the status code. I'd also rather not call my code from itself using curl or the like, due to performance concerns. Please let me know what you think.
Consider setting a constant:
define('HTTP_STATUS', 403);
and using the defined function later on:
if(defined('HTTP_STATUS') && HTTP_STATUS == 403) // ...or whatever you're looking to do
Actually peeking back at the headers themselves is kind of a hack in itself as it's simply too slow: you're dealing with strings and arrays and all sorts of other messy data. Set for yourself a simple constant: it's blazing fast, it does the same thing, and it doesn't create any "true" global variables.
http_response_code() in PHP 5.4 does this now.
It's another call, but as a last resort you could use this rather than curl. If you have php 5.0, What about get_headers()?

Categories