Reputation: 755
To keep it simple, I'm trying to display an image using php to help try and prevent any kind of a security loophole. I have the image being read through a php script and I am wanting to render it, so instead of going to http://example.com/path/to/uploads/dir/image.jpg
I want to have the user be able to go to http://example.com/path/to/script/image1
and have them be able to see the image.
This way I can hide the image path (http://example.com/path/to/uploads/dir/
) outside my document root (to where it can't be outright accessed by the domain path). So if the path to the domain was /path/to/public_html/
then I want the images uploaded to /path/to/uploads/
so you can't navigate to the uploads dir when surfing my domain.
My issue is the image I have been trying to render, won't render and I'm unsure as to why. The MD5 checksums are the same, and the HTTP headers are similar. The direct path to the image, compared to the desired path to the image.
I am using Laravel as a framework / backbone, but I don't think that matters to much, and my code to render the image is below
public function getImage($id){
$img = TitanImage::findOrFail($id);
// header('Content-type: image/jpeg');
// header('Content-Length: ' . filesize($img->path));
// header('Accept-Ranges: bytes');
// echo file_get_contents($img->path);
$file = $img->path;
$type = 'image/jpeg';
header('Content-Type:'.$type);
header('Content-Length: ' . filesize($file));
readfile($file);
// exit();
return;
}
I also used webconfs to check the headers of both of the desired image endpoints.
In regards to one of the comments about the intervention/image
package, I changed my code and I still get the same result; however, the content-length has changed, it's gotten longer.
public function getImage($id){
$img = TitanImage::findOrFail($id);
// header('Content-type: image/jpeg');
// header('Content-Length: ' . filesize($img->path));
// header('Accept-Ranges: bytes');
$file = $img->path;
return Image::make(trim($file,' '))->response();
}
In this edit, @Digitlimit mentioned checking to see if the image exists. This is my current code.
public function getImage($id){
$img = TitanImage::findOrFail($id);
$file = $img->path;
if(file_exists($file))
return Image::make($file)->response('jpg');
else
return 'File doesnt exist';
}
I also did test to see what would happen if I were to just return $file
instead of the Image::make
instance, I get the proper path, ie. when I go to SSH into the server and cd
to the path minus the image name the path exists and has permissions. When I do the ls -la
command it lists the image and it also has the proper permissions.
Upvotes: 1
Views: 1368
Reputation: 17553
If you have installed intervention image then do this:
public function getImage($id){
$img = TitanImage::findOrFail($id);
$file = $img->path;
return Image::make($file)->response('jpg');
}
Edited: I tested this on my project and it works perfectly:
Route:
Route::get('/api/v1/titan/image/{id}',function($id){
return \Image::make(storage_path("/images/$id.jpg"))->response('jpg');
});
Image location in my project:
Output when I visit URL:http://laravel.dev/api/v1/titan/image/1
Chrome Element Inspection
Upvotes: 0
Reputation: 57418
The code is working - the problem is it's sending extra information. The file is there, it is found, it is being sent. The link to your image returns:
HTTP/1.1 200 OK
Date: Wed, 17 Jun 2015 22:52:03 GMT
Server: Apache
Connection: close
Content-Type: image/jpeg
But the subsequent output is wrong:
00000050 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e 74 |: close..Content|
00000060 2d 54 79 70 65 3a 20 69 6d 61 67 65 2f 6a 70 65 |-Type: image/jpe|
00000070 67 0d 0a 0d 0a 20 ff d8 ff e1 19 57 45 78 69 66 |g.... .....WExif|
^^
`this 20 here, before the ff d8 ff of JPEG.
So this code (being only responsible for the JPEG part) is OK.
public function getImage($id){
$img = TitanImage::findOrFail($id);
$file = $img->path;
if (file_exists($file)) {
return Image::make($file)->response('jpg');
}
else {
return "File doesn't exist";
}
}
The extra space at the beginning of the data stream might come from some PHP file with an extra whitespace before the opening <?php
tag, or maybe after the closing tag.
For the latter, it is recommended that you do not close the <?php
tag, i.e. you never include the "?>" sequence.
For the former, try
public function getImage($id) {
return "*** is there a space before the asterisks?";
}
and observe the returned HTML. Unless the error is in TitanImage, which I believe unlikely, you should see the same space before the asterisks that is sent before the JPEG image. The file where the getImage()
function is defined is a likely suspect.
Otherwise, you can run "grep" to find PHP files that do not start with <?php
. You can modify this shameless plug by adding the -v
flag to grep
.
Upvotes: 2