Slim 3 Write Image as Response - php

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);

Related

PHP getting remote url image file size doesn't wait for content-length header to be set

I know this question has been asked millions of times, but please actually take the time to understand my problem before marking as duplicate or closing.
So I am using the following code. For some reason it gets all of the correct header information the first time I run the code EXCEPT for content-length. The second time I run the code it actually gets it correctly. I am retrieving the images from Facebook API if that changes anything.
function remote_filesize($url) {
$data = get_headers($url, 1);
if(isset($data['Content-Length'])) {
return (int) $data['Content-Length'];
}
else {
return -1;
}
}
Edit
Gotta love when you get downvoted with no explanation. Personally I think it should be required to provide a reason.
Anyway, this is still an issue, but in case anyone googling this needs a solution for getting the remote filesize, I would suggest using this awesome snippet from the PHP docs http://php.net/manual/en/function.filesize.php#114952
Sounds like a server caching issue.
So you may have to issue a full GET request instead of just a HEAD request.
Also, maybe check different casing -- 'content-length:' -- lowercase.

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

Trying to override Restler3 Content-Type

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;

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.

Categories