I am trying to display an image from a MySQL blob field. I have tried a few different things and none of them seem to work.
I have tried:
header("Content-type: $type"); img src = $blobData;
header("Content-type: $type"); echo($blobData);
<?php
header("Content-type: $type");
echo $blobData;
?>
This code looks perfectly OK. However, I heard a similar complain from another person and I was able to troubleshoot it by assuring that:
The php script does not output any extra character before or after sending the binary image data.
The php script is saved as a pure ASCII text file, not as a Unicode/UTF-8 encoded file. The Unicode/UTF-8 encoded PHP files might include a signature as the first bytes. These bytes will be invisible in your text editor but server will send these few extra bytes to the browser before the JPEG/GIF/PNG data. The browser will therefore find the wrong signature in the beginning of data. To workaround, create a blank text file in notepad, paste in the php code and save the file in ANSI encoding.
Another option you might consider (assuming you are on Apache):
Create an .htaccess file with a mod_rewrite for all image extensions (png, jpg, gif).
Have it redirect to a php script that looks up the image requested in the DB. If it is there, it echos out the header and BLOG. If it isn't there, it returns a standard 404.
This way you can have:
<img src="adorablepuppy.jpg" />
Which then gets redirected ala:
RewriteEngine on
RewriteRule \.(gif|jpg|png)$ imagelookup.php
This script does a query for the image, which (obviously) assumes that the requested image has a unique key that matches the filename in the URL:
$url = $_SERVER['REQUEST_URI'];
$url_parts = explode("/", $url);
$image_name = array_pop($url_parts);
Now you have just the image filename. Do the query (which I shall leave up to you, along with any validation methods and checks for real files at the address, etc.).
If it comes up with results:
header('Content-type: image/jpeg');
header('Content-Disposition: inline; filename="adorablepuppy.jpg"');
print($image_blog);
otherwise:
header("HTTP/1.0 404 Not Found");
FYI: I have no idea if this would be bad in terms of performance. But it would allow you to do what I think you want, which is output the image as though it were a flat image file on the server using a simple image element. I'm inclined to agree that BLOBs are not the best way to go, but this does avoid any cross-browser issues.
I believe that the issue that you are encountering is an issue with encoding. This resource claims that you can use the print function.
Just get the image from the database. And print it using the correct headers.
$image = mysql_fetch_array(...)
header("Content-type: image/jpeg"); // change it to the right extension
print $image['data'];
For performance reasons... this is not advisable. There are several reasons to put images in databases but the most common are:
a) keeping them indexed (duh!)
You can do this by storing the images flat on the server and just indexing the image filename.
b) keeping the image hidden/protected
Flickr and alike still store the images flat on the server and use a different approach. They generate a URL thats hard to find.
This link points to a protected image on my account. You can still access it once you know the correct URL. Try it!
farm2.static - a farm optimized for delivering static content
1399 - perhaps the server
862145282 - my username
bf83f25865_b - the image
In order to find all my secret images any user can hard hit Flickr with the above address and change the last part. But it would take ages and the user would probably be blocked for hammering the server with thousands of 404s.
That said there is little reason to store images on BLOBs.
Edit:Just a link pointing to someone that explained much better than I did why BLOB is not the way to go when storing images.
Related
As an example, say I'm trying to download App Icons from the Google Play store for a service. Here is an example URL:
https://lh6.ggpht.com/1eVPA6Iukw-F4i5xq1ZWicaKBzmprLGw98YhdG20E-wlsHHg3PcKJqbY_fWLdJeGRw=w512-rw
There is no mime type associated with the data provided, and when the file is saved any image viewers (or at least the ones I've tried) will say the file is corrupt. They will show up in Chrome and a couple of other things, but when inspecting the data, it's clear there's simply no mime type. This is an issue, because I am further using these data streams in other scripts which require that they be recognized as a specific type. (namely PNG)
I've tried things such as:
imagepng(imagecreatefromstring($icondata), $finaldir.'/icon.png');
Where $icondata is simply a curl response for the image. This will return an error saying that the data is of an unknown format for the imagecreatefromstring function. Of course, I've also tried:
file_put_contents($finaldir.'/icon.png', $icondata);
To no avail. It creates the file, but as I said, the image is not recognized as an image in most applications and in various analyzing functions. Is there a way to specifically set the mime type of a given string of data? Or some other workaround I'm not quite seeing?
Edit: Also, to note, there is nothing wrong with the $icondata variable. I have tried manually saving the image to a file through my web browser, and the same problem arises.
I have developed a small CMS for myself and was facing the same issue. After trying a lot, I have found a solution. It is working for me and I hope you will find it useful for your project too.
Regarding the corruption of file, for Chrome user-agent, Google servers send icons as .webp format and you need a PHP library for handling images of this type. And for other user-agents (like Firefox), images are sent as PNG.
Now comparing the two URLs for a same icon in Firefox or Chrome, you will notice that image paths generated for Chrome contain -rw at the end while the same URL in Firefox doesn't contain that -rw.
Not digging very deeper, simply remove the -rw from the end of the URL and copy the image. You will get a PNG image. A hint is here for you:
<?php
$image_path = "https://lh5.ggpht.com/8PODwBXKk4L201m4IO1wifRDfbn4Q1JxNxOzj-5TXPJ85_S-vOqntLi7TsVyeFQM0w4=w300-rw"; // Firefox app on Google Play
$png_path = substr($image_path, 0, -3);
copy($png_path, 'file.png');
?>
This will save the image as PNG. Please note that I have used substr() function to remove -rw from the end. To make it precise, you may use any other way to fix that part of the path.
P.S. You may also try sending a custom user-agent (i.e. Firefox) with your CURL request to receive the PNG path so you will not need to fix it by yourself :)
You can use HttpResponse::getContentType to determine type of content you're getting from URL
This not a png, but WebP
You can use it in PHP with
imagecreatefromwebp( string $filename );
More information:
- https://developers.google.com/speed/webp/
- http://php.net/manual/function.imagecreatefromwebp.php
I am trying to read multiple image files from a folder (.htaccess protected) and display in a HTML page using php readfile().
The problem is I can see only the first image is read and the next is not shown in the browser. The code is as below
<?php
$image1 = 'files/com_download\256\50\www\res\icon\android\icon-36-ldpi.png';
$image2 = 'files/com_download\256\50\www\res\icon\android\icon-48-mdpi.png';
$imginfo = getimagesize($image1);
header("Content-type: ".$imginfo['mime']);
readfile($image1);
$imginfo = getimagesize($image2);
header("Content-type: ".$imginfo['mime']);
readfile($image2);
?>
I could see the first image 'icon-36-ldpi.png' successfully read and displayed in the browser and the second image is not read and not displayed in the browser.
Am I missing something? Any advice please.
Sorry if I am doing stupid but the requirement is to read multiple image files and render in the browser like a grid view. I cannot use img tag because of security reasons.
You can't dump both images out at once. Why not make two images in your html so the browser makes two calls to your script. Then use a GET param to pass the filename you want to display.
---Edit---
Important Security Note
There is an attack vector which you open up when doing soething like this. Someone could easily view your source html and change the parameter to get your image script to output any file they want. They could even use "../../" to go up directories and search for well known files that exist. e.g. "../../../wp_config.php". Now the attacker has your wordpress database credentials. The correct way to prevent against this is to always validate the input parameter properly. For example, only output if the file name ends with ".jpg"
I want to have a PNG picture, but when accessing it, it runs a PHP script, the PHP script should decide what picture to send (using some if statements and whatever). Then the PHP script should read the image file from somewhere on my web server and output it.
Here is the issue, if I get a .png file, and put PHP code in it, it won't work, however, if I use the .php extension, it works, and I can even embed the image into other websites, and the PHP can decide what image to send, but if I want to view that image directly (copy it's URL into my address bar) it doesn't work, it gives me the images plain contents (random jibberish).
Anyone know what to do?
Also This is my first question on Stack Overflow - please tell me if I am doing something wrong.
You need to send Content-Type headers.
For png:
header('Content-Type: image/png');
For others change png to jpg or gif or bmp or whatever.
Please note that header() function must be used before anything is written to output.
First, make sure you have your image image.png somewhere accessible to php.
Then create a php script image.php:
<?php
header('Content-Type: image/png');
readfile('image.png');
The script now acts like it was a PNG image.
It sounds like you know how to send the image, your issue is that you want the URL to look like it's a PNG image.
There are a couple of things you can do. First, if your web server supports URL rewriting (like Apache's mod_rewrite module), you can use a rewrite rule so that the user access the script as something like http://example.com/generated_image.png but your server will translate/rewrite this URL to point directly to your PHP script, so something like /var/www/image_generator.php.
Another option would be to actually name your script "generated_image.png" but force your webserver to treat it like a PHP script. For instance, in Apache you could try something like:
<Location /generated_image.png>
ForceType application/x-httpd-php
</Location>
As a final note, if you're not actually worried about the URL, but worried about the file name that is used if the user decides to save it to disk, you can simply use the Content-Disposition HTTP header in your response. In PHP it would look something like this:
<?php
header("Content-Disposition: inline; filename="generated_image.png");
?>
With that, it doesn't matter what the URL is, if the user saves the image through their web browser, the web browser should offer "generated_image.png" as the default filename.
Simplest version I know...
<?php
header('Content-Type: image/png');
if(whatever)
{
$image=your_image_select_function();
}
// as suggested by sh1ftst0rm with correction of unmatched quotes.
header('Content-Disposition: inline; filename="'.$your_name_variable.'"');
readfile($image);
?>
Then, you treat it like an image file. That is, if this is "pngmaker.php" then, in your HTML document, you do
<img src="pngmaker.php">
You can even do
<img src="pngmaker.php/?id=123&user=me">
I want code that loads an image to a PHP server and then send it to browser.
For example I want sample.php to send an image to browser once it is requested.
in other words, I want to create a PHP file that acts like a proxy for an image.
why are you doing this?
why don't deliver the image directly?
if you are trying to display a random image you may as well just redirect to the image using
header("Location: address-of-image");
for delivering the file to your clients from your server and not from its original location you can just do. however your php.ini settings need to allow external file opens
readfile("http://www.example.com/image.jpg")
correct headers are not required if you are going to display the image in an img tag,
altough i would recommend it. you should check the filetype of the image or in most cases just set an octet-stream header so the browser doesnt assume an incorrect type like text or something and tries to display binary data.
to do so just do
header("Content-type: application/octet-stream")
one more thing to consider may be setting correct headers for caching...
You need to use
$image = fopen("image.png");
Modify the headers(not sure exacly if it's correct)
headers("Content-type: image/png");
And then send the image
echo fread($image, file_size("image.png"));
What would be the best practice way to handle the caching of images using PHP.
The filename is currently stored in a MySQL database which is renamed to a GUID on upload, along with the original filename and alt tag.
When the image is put into the HTML pages it is done so using a url such as '/images/get/200x200/{guid}.jpg which is rewritten to a php script. This allows my designers to specify (roughly - the source image maybe smaller) the file size.
The php script then creates a hash of the size (200x200 in the url) and the GUID filename and if the file has been generated before (file with the name of the hash exists in TMP directory) sends the file from the application TMP directory. If the hashed filename does not exist, then it is created, written to disk and served up in the same manner,
Is this efficient as it could be? (It also supports watermarking the images and the watermarking settings are stored in the hash as well, but thats out of scope for this.)
I would do it in a different manner.
Problems:
1. Having PHP serve the files out is less efficient than it could be.
2. PHP has to check the existence of files every time an image is requested
3. Apache is far better at this than PHP will ever be.
There are a few solutions here.
You can use mod_rewrite on Apache. It's possible to use mod_rewrite to test to see if a file exists, and if so, serve that file instead. This bypasses PHP entirely, and makes things far faster. The real way to do this, though, would be to generate a specific URL schema that should always exist, and then redirect to PHP if not.
For example:
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
So if a client requests /images/cached/<something> and that file doesn't exist already, Apache will redirect the request to /images/generate.php?/images/cached/<something>. This script can then generate the image, write it to the cache, and then send it to the client. In the future, the PHP script is never called except for new images.
Use caching. As another poster said, use things like mod_expires, Last-Modified headers, etc. to respond to conditional GET requests. If the client doesn't have to re-request images, page loads will speed dramatically, and load on the server will decrease.
For cases where you do have to send an image from PHP, you can use mod_xsendfile to do it with less overhead. See the excellent blog post from Arnold Daniels on the issue, but note that his example is for downloads. To serve images inline, take out the Content-Disposition header (the third header() call).
Hope this helps - more after my migraine clears up.
There is two typos in Dan Udey's rewrite example (and I can't comment on it), it should rather be :
RewriteCond %{REQUEST_URI} ^/images/cached/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule (.*) /images/generate.php?$1 [L]
Regards.
One note worth adding is to make sure you're code does not generate "unauthorized" sizes of these images.
So the following URL will create a 200x200 version of image 1234 if one doesn't already exist. I'd highly suggest you make sure that the requested URL contains image dimensions you support.
/images/get/200x200/1234.jpg
A malicious person could start requesting random URLs, always altering the height & width of the image. This would cause your server some serious issues b/c it will be sitting there, essentially under attack, generating images of sizes you do not support.
/images/get/0x1/1234.jpg
/images/get/0x2/1234.jpg
...
/images/get/0x9999999/1234.jpg
/images/get/1x1/1234.jpg
...
etc
Here's a random snip of code illustrating this:
<?php
$pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']);
if(file_exists($pathOnDisk)) {
// send header with image mime type
echo file_get_contents($pathOnDisk);
exit;
} else {
$matches = array();
$ok = preg_match(
'/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/',
$_SERVER['REQUEST_URI'], $matches);
if(! $ok) {
// invalid url
handleInvalidRequest();
} else {
list(, $width, $height, $guid) = $matches;
// you should do this!
if(isSupportedSize($width, $height)) {
// size is supported. all good
// generate the resized image, save it & output it
} else {
// invalid size requested!!!
handleInvalidRequest();
}
}
}
// snip
function handleInvalidRequest() {
// do something w/ invalid request
// show a default graphic, log it etc
}
?>
Seems great post, but my problem still remains unsolved. I dont have access to htaccess in my host provider, so no question of apache tweaking. Is there really a way to set cace-control header for images?
Your approach seems quite reasonable - I would add that some mechanism should be put into place to check that the date the cached version was generated was after the last modified timestamp of the original (source) image file and if not regenerate the cached/resized version. This will ensure that if an image is changed by the designers the cache will be updated appropriately.
That sounds like a solid way to do it. The next step may be to go beyond PHP/MySQL.
Perhaps, tweak your headers:
If you're using PHP to send MIME types, you might also use 'Keep-alive' and 'Cache-control' headers to extend the life of your images on the server and take some of the load off of PHP/MySQL.
Also, consider apache plugin(s) for caching as well. Like mod_expires.
Oh, one more thing, how much control do you have over your server? Should we limit this conversation to just PHP/MySQL?
I've managed to do this simply using a redirect header in PHP:
if (!file_exists($filename)) {
// *** Insert code that generates image ***
// Content type
header('Content-type: image/jpeg');
// Output
readfile($filename);
} else {
// Redirect
$host = $_SERVER['HTTP_HOST'];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = $filename;
header("Location: http://$host$uri/$extra");
}
Instead of keeping the file address in the db I prefer adding a random number to the file name whenever the user logs in. Something like this for user 1234: image/picture_1234.png?rnd=6534122341
If the user submits a new picture during the session I just refresh the random number.
GUID tackles the cache problem 100%. However it sort of makes it harder to keep track of the picture files. With this method there is a chance the user might see the same picture again at a future login. However the odds are low if you generate your random number from a billion numbers.
phpThumb is a framework that generates resized images/thumbnails on the fly. It also implements caching and it's very easy to implement.
The code to resize an image is:
<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&h=200" alt="thumbnail"/>
will give you a thumbnail of 200 x 200;
It also supports watermarking.
Check it out at:
http://phpthumb.sourceforge.net/