Output image to browser AND write to disk - php

This seems like a SUPER easy question for people who knows PHP but I can't figure out how to make this work (probably because I know VERY little about PHP). Most question related to this asks how to output an image to either browser or disk, but I wanna do both. See example below:
<?php
header('Content-type: image/png');
$filename = "my_written_image.png";
$png_image = imagecreatefrompng('some_fancy_image.png');
imagepng($png_image, $filename);
imagepng($png_image);
?>
This won't work. The image won't show in the browser, but it will work if I remove this line: imagepng($png_image, $filename);
I'm guessing one can only "output" one thing using imagepng but how will I accomplish the above?

You should use the following code:
<?php
header('Content-type: image/png');
$filename = "my_written_image.png";
$png_image = imagecreatefrompng('some_fancy_image.png');
file_put_contents($filename, $image);
imagepng($png_image, $filename);
?>
My server is not turned on so I can't test the code but I think this should work.

Okay it seems my original solution actually did work. The problem was I was using (in my real code): if(readfile("myfile.png")) and this will return false if it's not found, but it will also throw an error if #readfile() is not used (note the #). The docs said:
an error message is printed
I didn't think this would cause the whole thing to fail. Sorry for my stupidness.

Related

Displaying Image Stored as Binary in Postgre bytea Column

I'm stuck for hours working on this. Few solutions found over the Net but no one seems to help me. I am having problem to display an image on the browser using PHP that takes the image from Postgres DB with column type bytea. I'm sure I'm missing something here. So some guidance are really appreciated. So I have this code below:
$prod = new Product();
$prod->display_latest_product();
if( $prod->exists() ){
$products = $prod->data();
foreach($products as $product){
echo $product->id;
echo $product->binarydata;
/* Solution below: I only get one image with broken link */
header('Content-type: image/png');
echo pg_unescape_bytea($product->binarydata);
/* Solution below: I only get one image with broken link */
header('Content-Type: image/png');
$data=fgets($product->binarydata);
print(pack('H*',$data));
/* bin2hex() expects parameter to be string but resource given */
echo bin2hex($product->binarydata);
/* Solution below: I only get one image with broken link */
$image = stripcslashes($product->binarydata);
header("Content-Type: image/png");
print($image);
}
}
I appreciate some explanation on this because I am still confuse after research and reading.
Finally I found the way to do it. Based on what I found in Handling Binary Data with PDO as I am using PDO to read the column in DB.
So I put these two lines in my foreach loop:
header("Content-Type: ".$product->mimetype);
fpassthru($product->binarydata);
And my file is displayed nicely. As #Musa pointed out that I can only print one image at a time, so I am going to use img with src="thepage.php?img=xx" just to display the image. I am developing e-Commerce app so not sure if this can affect performance because lots of images will be loaded. Any comments or suggestions are welcomed. Anyway I hope this could help people out there who is having same problem.
Documentation on fpassthru is here.
EDIT::SOLUTION FOUND
So I have finally got the real solution that tackles my problem defined in the comment below. And this time it does not involve PHP header at all.
foreach($products as $product){
ob_start(); // Let's start output buffering.
fpassthru($binarydata); //This will normally output the image, but because of ob_start(), it won't.
$contents = ob_get_contents(); //Instead, output above is saved to $contents
ob_end_clean(); //End the output buffer.
$dataUri = "data:image/png;base64," . base64_encode($contents);
echo "<img src='$dataUri' />";
}
I have got the solution here. And based on the comment in that thread, the trick is actually at the buffering. ob_start has to be used in pair with ob_end_clean(). Hope this helps people out there. Thanks.
Assuming that $product->binarydata has contents fetched from the BYTEA column, this method does work:
header('Content-type: image/png');
echo pg_unescape_bytea($product->binarydata);
except when having the client/server version mismatch mentioned in this answer, in which case the escape format for bytea should be used.
The code must not output anything else than the two lines above.

How do you return an image without the filename or extension on the url

So there is this webpage where this guy managed to return raw images from the server
just by typing the id as a parameter.
http://photos.iitm.ac.in/byid.php?id=008576
even if you right click the image and open in a new tab, only the php gets opened.
does anyone know how he managed to do this?
I need this kind of functionality for profile pics
It's pretty simple. You just have to send the data with the right Content-type. So if you want to show a gif-image just uste:
Header("Content-Type: image/gif");
and then send out the image data.
You can do like this :
Suppose example URL is :
http://www.example.com/getImage.php?id=20
So, on getImage.php page get user image information from database and provide the image source :
Code should be like this:
$userImageName="testImage.gif"; //FROM DATABASE FOR id=20, Just for example
ob_clean(); //CLEAN THE OUTPUT BUFFER
header("Content-Type: image/gif"); //SET PAGE HEADER FOR IMAGE
echo file_get_contents('imageDirectory/'.$userImageName);
die;
Although it's not a direct answer to the asked question, since it was already answered by other people, I think it's nonetheless worth mentioning.
You can also control the file name that appears when you try to save the picture! To do that, use following header:
header('Content-Disposition', 'inline;filename=my_image_title.jpg');
so that your script looks like this:
header('Content-Disposition: inline;filename=my_image_title.jpg');
header('Content-Type: image/jpeg');
readfile($pathToImage);
//or echo $imageContent
Just make sure that you didn't accidentally output anything before making first call to header(), otherwise you might get "headers already sent" error.

imagepng Very Slow

I have a .php file that's supposed to load an image for display in an img tag(i.e., <img src="the_file.php?which=0"/>). It looks like this:
<?php
ob_clean();
header("Content-type: image/png");
include_once("util.php");
//Do a simple calculation to get $name from (int)$_GET["which"];
$im = imagecreatefrompng("protected_directory/".$name.".png");
imagepng($im,NULL,0,NULL);
imagedestroy($im);
ob_end_flush();
?>
It works correctly, but the image loads substantially slower than just loading it directly(i.e. <img src="protected_directory/the_name.png"/>, where "the_name" was calculated the same way as in the PHP file, but I can't just do this because the protected_directory isn't world readable).
My question is, why is this suddenly so much slower? It's not a large image, but nor is it terribly small.
If you're just displaying an existing file, use readfile() to output it to the browser. There's no need to go through all the overhead of creating an editable GD object for this.
imagepng is known to be slow, if you need to output images with a PHP script, use code like this:
$filename = md5(time() . mk_rand());
imagepng($im, $filename);
echo file_get_contents($filename);
As another answer, I figured out that you can use the third parameter to compress the image (PNG uses zlib). Setting it to 9 works about as well as the other solutions.

readfile equivalent for binary data?

I'm using http://undesigned.org.za/2007/10/22/amazon-s3-php-class/documentation to access private files using php. I can get the data of the file by saying $object->body. I actually want to see the image in the browser or play the video in a video player. Is there a way to do that?
I think I need something like readfile. The problem is readfile is I need the path to the file. The path is private so I cannot use that. Is there a way to do a readfile of the binary data?
I put this in the php thinking this would help but it still displays the binary data.
header('Content: image/jpeg');
header('Content-Disposition: inline; filename=IMAG0108.jpg');
echo $object->body;
You just set the content-type header and output the readfile to the browser. What I do is create a new php file, like "showimage.php", that accepts an ID or some such to know what image to display. Then I use it in a browser page: .
In showimage.php, something like:
<?php
header('Content-type: image/png');
readfile('/var/images/' . $_GET['id'] . '.png');
// or
// echo $object->body;
?>
That would read a file from the local system and output it as an image. Off the top of my head, so I might have messed up that code!
header('Content: image/jpeg');
echo $object->body;
Should work fine (for JPEGs), you need know what filetype is in question and then send appropriate content headers.

content-type failing in firefox when using dynamic images (PHP) in <img src="source.php">

Okay excuse the cryptic subject.
I have a system which dynamically fetches image data and does some modification on the fly.
Essentially, missing out the unimportant bits, this is my code:
$File->Filename = "testimage.jpg";
$File->Open();
$FileData = $File->Read();
header('Content-Type: image/jpeg');
echo $FileData;
The only output on the page is $FileData. Okay. When I run the script as is, Firefox presents me with a blank page and Chrome and IE give me a 'missing picture' box.
However oddly enough, when I remove the Content Type declaration, I can see the raw image data just fine. I have tested this with several images, granted all of the JPEG type but it clearly loads up the different pictures just fine, as the raw data changes successfully, and matches the raw content of the image itself.
Anyone have any idea why it would be failing to just display the image at this point?
You need to give more information in order to let the browser handle it correctly (use the correct type and length):
header('Content-Length: '.strlen($FileData),true); // EDIT: inserted the strlen function as suggested by kgb
header('Content-Type: image/jpeg');
Try setting Content-Length appropriately. Remove the trailing ?> to make sure there is no whitespace at the end of the script and ensure that the starting it at the very start of your script.
i'll combine phant0m's and Thariama's answers ;):
header('Content-Length: '.strlen($FileData), true);
header('Content-Type: image/jpeg');
die($FileData);

Categories