Trying to override Restler3 Content-Type - php

I'm very new to Restler3. And a very happy new user!
My object was basically to setup a EC2 which using Restlers clever routing can rewrite streaming manifests (the manifest basically tells which fragments of video/audio/subtitle to stream).
All is very good. Restler gets the Manifest, does the rewriting and easily sends it back to requestor.
Now I am trying to squeeze something else into Restler. I need Restler to respond with an MP4-header formatted XML-Subtitle-TTML chunk.
You might ask, why squeeze this onto a Restler-platform?
A. The routing in Restler makes everything so much easier.
B. Why not try it out?
So, I have managed to get Restler to do almost what I need. I simply bypass Restlers return statement. I simply echo() out the binary data to requestor. And amazingly it all works.
My only tiny problem left to sort out is Content-Type.
All my other "normal" xml-requests return "text/html" when testing with this awkward way of returning the response, using simple echo-statements of nicely handcrafted XML. So I try to override with
header('Content-type: text/xml');
Which also gets returned.
The problem is that somehow the binary response with an MP4-header gets forced by "someone" into
Content-Type: application/json; charset=utf-8
although I have set
header('Content-type: text/xml');
Any clues what I could do to override this?

Easiest way to fix headers Content-type is by adding this header and then exiting your function. And by doing the exit; cheating Restler into replying with the (maybe non-standard) Content-type.
header('Content-type: text/xml');
exit;

Related

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

Slim 3 Write Image as Response

I've been researching this for hours and Google hasn't been any help. How can I use Slim 3 to write an image as the response? No matter what I've tried, the binary data is displayed instead of the image. Here's the first piece of code I tried.
$image = file_get_contents("image_location");
return $response->withHeader("Content-Type", "image/jpeg")->write($image);
Beyond that, I've added various headers such as Content-Disposition and Content-Length. Tried outputting as base64. If you find a Google result for it, odds are I tried it. Nothing works. Of course this simple PHP works fine in a standalone file, but not in Slim.
header("Content-Type: image/jpeg");
readfile("image_location");
My guess is that when Slim outputs it does something to the data, but I'm not sure. Worst case scenario I just create a template and output the base 64 as an img src. I was trying to avoid that.
UPDATE After some investigation it seems like the content-type is being reset to text/html, but I'm not sure why. Any insight is welcome.
For those who are curious, I found the solution. I traced it down to my middleware in which I had $next($request, $response); however I neglected to assign the return value to $response, so Slim was setting the response to default values.
Now I know to make sure middleware includes the following:
$response = $next($request, $response);

How does get_headers work in the background

I tryied searching for this and I belive I alredy know the answer but it's crusal that I'm not wrong, so here I go..
When calling get_headers, will I retrieve the whole file even though the function only returns the headers or will it retrieve, as expected, only the headers and nothing else?
I'm guessing the last but if I'm wrong this will cause some serious problems..
Also I noticed that there is a global setting I can change to send a HEAD request instead of the default GET request, witch is why I'm asking my self whats really going on.
Edit
Maybe this function is a better alternative? stream_get_meta_data or do they actually do the same thing?
You could also take a look at the source code, if you are familiar with C.
The function is defined here. I quickly looked over this, and it seems it is a header-only request, see line 715:
STREAM_ONLY_GET_HEADERS
GET
Requests a representation of the specified resource. Requests using
GET should only retrieve data and should have no other effect. (This
is also true of some other HTTP methods.) The W3C has published
guidance principles on this distinction, saying, "Web application
design should be informed by the above principles, but also by the
relevant limitations."
HEAD
Asks for the response identical to the one that would correspond to a
GET request, but without the response body. This is useful for
retrieving meta-information written in response headers, without
having to transport the entire content.
Wikipedia/Hypertext_Transfer_Protocol
The PHP-docs clearly states that normal get_headers() uses a GET-request, but you can force it to use HEAD instead, like this:
<?php
// By default get_headers uses a GET request to fetch the headers. If you
// want to send a HEAD request instead, you can do so using a stream context:
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
)
);
$headers = get_headers('http://example.com');
?>
Unfortunaley you're right, just read the PHP manual:
get_headers() returns an array with the headers sent by the server in response to a HTTP request.
Also take a look at the examples.
Okay, next time I should spend more attention to the question formulation.
Yeh, if the request type is set to GET (standard) you will get the whole content. You could change it to HEAD, but this is not what you want.

Enabling CORS in CakePHP app

I am trying to enable CORS for an API built in CakePHP so that all requests are accessible with the following in the AppController:
public function beforeFilter()
{
header("Access-Control-Allow-Origin: *");
}
Is this in the wrong place? As requests are still being blocked.
Update: It seems this does in fact work BUT because I am doing something like:
header('Content-Type: application/json');
echo json_encode(array('message'=>'Hello world!'));
In some of my methods it's acting as though it's overriding the header set the AppController so it's not appearing in the response for the JSON calls.
Any ideas?
Update 2: Returning JSON like below, fixes the problem:
$this->response->type('json');
$this->response->body(json_encode(array('message'=>'Hello world!')));
So apparently using header() in Cake breaks previous headers?
You can do this using the cake response object;
$this->response->header('Access-Control-Allow-Origin', '*');
More info on the response object;
http://book.cakephp.org/2.0/en/controllers/request-response.html#setting-headers
However, the beforeRender() callback seems a more logical location.
Another option is to add this header in your apache vhost or htaccess examples can be found in the htaccess file of Html5Boilerplate which is a very interesting thing to look at (well documented), because it contains a lot of optimisations that work nicely with cakephp as well;
https://github.com/h5bp/server-configs-apache/blob/master/dist/.htaccess
http://html5boilerplate.com/
Based on what I found out here: Sending correct JSON content type for CakePHP
The correct way to return JSON in CakePHP is like so:
$this->response->type('json');
$this->response->body(json_encode(array('message'=>'Hello world!')));
This is because the headers can be overridden and therefore the CORS doesn't work unless you do it the 'proper' way using the response object in Cake.

Can't send content-type: text/xml header from PHP at the same time getting the data from MYSQL

i hope you can cast some light on my problem. I need to do an AJAX / PHP / MYSQL application to display posts and stuff on the page i'm writing.
I only discovered how to do some simple stuff in PHP after taking some mushrooms but that was years ago and now i don't have mushrooms and i'm just stuck!
So here's the problem:
i think i need to send a proper "xml" file through php so the ajax part can take it but: when i try to put the header on top of the php it displays this error:
" Extra content at the end of the document "
When i looked at some tutorials people were using the "header" fearlesly to do such stuff as i want to do and no comments suggested that it didn't work. so why it doesn't work on my local server?
I'm running:
WAMP
Apache 2.2.11
PHP 5.3.0
It also doesn't work on a remote server (PHP 5.3.0) :/
I read all the stuff i could find till 5am and decided to ask you for help for the first time :)
Thank you!
header('content-type: application/xhtml+xml; charset=utf-8');
require_once("allyouneed.php");
require_once("bazingablob.php");
$category=$_GET["category"];
$post_tags=$_GET["post_tags"];
$language=$_GET["language"];
$author=$_GET["author"];
$posts_per_page=$_GET["posts_per_page"];
$current_page=$_GET["current_page"];
$order=$_GET["order"];
$hard_limit=$_GET["hard_limit"];
$show_hidden=$_GET["show_hidden"];*/
$wypluj="";
$wypluj="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
$bazinga_blob = new bazingablob;
if (!$bazinga_blob->connect_to_database())
{
$wypluj.="<IsOK>0</IsOK>";
echo $wypluj;
exit;
}
else
{
$wypluj.="<IsOK>jedziem</IsOK>";
}
$bb_result=$bazinga_blob->get_all_posts($category,$post_tags,$language,$author,$posts_per_page,$current_page,$order,$hard_limit,$show_hidden);
if ($bb_result) //udalo sie cos znalezc w bazie wedlug kryteriow
{
$wypluj.="<Pagination>";
$wypluj.="<CurrentPage>";
$wypluj.=$bazinga_blob->posts_pagination["current_page"];
$wypluj.="</CurrentPage>";
$wypluj.="<LastPage>";
$wypluj.=$bazinga_blob->posts_pagination["last_page"];
$wypluj.="</LastPage>";
$wypluj.="<PostsCount>";
$wypluj.=$bazinga_blob->posts_pagination["posts_count"];
$wypluj.="</PostsCount>";
$wypluj.="</Pagination>";
$wypluj.="<Posts>";
foreach ($bb_result as $item)
{
$wypluj.="<Post>";
$wypluj.="<PostId>".$item->post_id."</PostId>";
$wypluj.="<PostAuthor>".$item->post_author."</PostAuthor>";
$wypluj.="<PostLangId>".$item->post_langid."</PostLangId>";
$wypluj.="<PostSlug>".$item->post_slug."</PostSlug>";
$wypluj.="<PostTitle>".$item->post_title."</PostTitle>";
$wypluj.="<PostGreetingPicture>".$item->post_greeting_picture."</PostGreetingPicture>";
$wypluj.="<PostGreetingVideo>".$item->post_greeting_video."</PostGreetingVideo>";
$wypluj.="<PostGreetingSound>".$item->post_greeting_sound."</PostGreetingSound>";
$wypluj.="<PostShort>".$item->post_short."</PostShort>";
$wypluj.="<PostBody>".$item->post_body."</PostBody>";
$wypluj.="<PostDate>".$item->post_date."</PostDate>";
$wypluj.="<PostPublished>".$item->post_published."</PostPublished>";
$wypluj.="<PostSticky>".$item->post_sticky."</PostSticky>";
$wypluj.="<PostComments>".$item->post_comments."</PostComments>";
$wypluj.="<PostProtected>".$item->post_protected."</PostProtected>";
$wypluj.="</Post>";
}
$wypluj.="</Posts>";
}
echo $wypluj;
The error comes from your browser and indicates that your XML is malformed.
Setting the application/xhtml+xml header tells the browser to process the document as serious XML. XML needs to be "well-formed", i.e. it must not contain any syntax errors. Apparently you do have a syntax error on line 1 at column 73, which makes the browser abort the attempt to process the document.
For this reason it's a pain to hand-code XML, you should really look into a library that takes care of the well-formedness for you, like PHP's own XMLWriter.
Have you validated your XML?
http://friendsofed.infopop.net/4/OpenTopic?a=tpc&s=989094322&f=5283032876&m=4521066061
I'm honestly not sure what you're trying to do with the header, it's not any Ajax method I've ever been taught. The header method you're doing looks just a few lines short of outputting the XML to a download prompt.
Here's my favorite way to do AJAX. Simple, understandable, and quick.
Include Jquery.
Setup your data--whether by form with a Serialize (gets form data into a Javascript Variable) or by just setting some variables as it seems you're doing above.
Send via Jquery Ajax to a separate processing page. The page will receive the data you setup as a $_REQUEST variable, with the method depending on whether you defined it as a POST or not (defaults to a GET)
The processing page --does-- stuff with the REQUEST data and may or may not respond back to the page. This is where you can do stuff like update divs, alert that it worked, etc.
Here's a great tutorial. Focus on the code under "Hello Ajax, Meet Jquery"
If you get yourself any more of those mushrooms, a PHP familiar way to do AJAX is with XAJAX. It allows you to do asynchronous calls to PHP functions. Be aware, though, that the forums are not the most english-friendly and documentation is a bit cryptic.

Categories