I want to be able to retrieve a remote image from a webserver, resample it, and then serve it up to the browser AND save it to a file. Here is what I have so far:
$ch = curl_init();
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "$rURL");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
// grab URL and pass it to the browser
$out = curl_exec($ch);
// close cURL resource, and free up system resources
curl_close($ch);
$imgRes = imagecreatefromstring($out);
imagejpeg($imgRes, $filename, 70);
header("Content-Type: image/jpg");
imagejpeg($imgRes, NULL, 70);
exit();
Update
Updated to reflect correct answer based on discussion below
You can fetch the file into a GD resource using imagecreatefromstring():
imagecreatefromstring() returns an image identifier representing the image obtained from the given data. These types will be automatically detected if your build of PHP supports them: JPEG, PNG, GIF, WBMP, and GD2.
from there, it's pretty straightforward using imagecopyresampled().
Output it using imagejpeg() or whichever output format suits you best.
Make one output with a file name:
imagejpeg($image_resource, "/path/to/image.jpg");
then send the same resource to the browser:
header("Content-type: image/jpeg");
imagejpeg($image_resource);
depending on the image's format, you may want to use the imagepng() or imagegif() functions instead.
You may want to work with different output formats depending on the input file type. You can fetch the input file type using getimagesize().
Remember that you can adjust the resulting JPEG image's quality using the $quality parameter. Default is 75% which can look pretty crappy.
Related
So I've been using this approach to resize images uploaded via forms in PHP:
list ($width, $height, $type, $w)=getimagesize($_FILES[$imageName]['tmp_name']);
$info = getimagesize($_FILES[$imageName]['tmp_name']);
This works well - allows resizing & conversion to png.
Now I need to do the same thing - but for downloaded images, e.g. given the url of an image online such as http://colorvisiontesting.com/images/plate%20with%205.jpg.
From the looks of it this can be done with CURL, but I can't quite work out how to then create an image object from it. This is what I have so far:
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($c, CURLOPT_URL, $imageURL);
$curlImage = curl_exec($c);
$err = curl_getinfo($c,CURLINFO_HTTP_CODE);
curl_close($c);
list ($width, $height, $type, $w)=getimagesize($curlImage);
$info = getimagesize($curlImage);
But this is failing at getimagesize - and I can't work out what the correct approach is here. Any ideas?
The getimagesize function works on filename (local or remote) but not on a string which represents the content of your image.
You can:
Save that content to a local file (using file_put_contents, for example)
Use the getimagesize function on the remote file (it should work).
Use the getimagesizefromstring (which works the same as getimagesize but works in data and not filename)
Use the imagecreatefromstring (which you need if you want to convert your stream/data to image (gd) resource, and then use the imagesx and imagesy on the resouce.
I'm trying to retrieve a remote image, but when I view the image (either output straight to browser or saved to disk and viewed) the quality is always lower.
Is there a way to do this without quality loss? Here are the methods I've used, but with the same result.
$imagePath is a path like http://www.example.com/myimage.jpg and $filePath is where the image will be saved to.
curl
$ch = curl_init($imagePath);
$fp = fopen($filePath, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
file_get_contents
$tmpImage = file_get_contents($imagePath);
file_put_contents($filePath, $tmpImage);
I'll get a screenshot to show the quality issues shortly.
If you look around the KIA logo you can see of the left the quality issues I'm having.
Update:
Upon some further testing with different images it seems the quality issues are different with each image. Some has no issues at all.
Also the image which the screenshots are from above, based on the long url to the image, it seems like the image has already been resized and had it's quality alter before it gets to my script, so I'm thinking that could account for these issues too.
I'm saving and resizing tons of images from a remote server using cURL in PHP, but the previous developer doesn't implemented any kind of system for make the user uploaded pictures "safe", so the users were able to upload any kind of file format with any kind of name then the uploaded files name is saved to a database as is, so lots of files have non URL safe and iso-8859-8 characters. For example:
gaght101125659_5 Gn-eŐs mtó gÁrlós.jpg
According to this answer I made a code for getting the pictures.
private function getRemoteUrl($file)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $file);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
$img = imagecreatefromstring($this->getRemoteUrl($url));//$url contains the plain url of the image.
This code works perfectly for images with a name like gaht123115516_2.jpg but for the example shown above it gives an error saying:
Warning: imagecreatefromstring() [function.imagecreatefromstring]: Data is not in a recognized format in /home/test/public_html/resizing.php on line 64
Of course, because of the fancy characters. So what should I do in getRemoteUrl($file) with the $file variable to make it work? Can this be done in PHP? If not what other methods/programming languages should I try?
Use urlencode() on the filename. don't urlencode() the entire url.
URL encode the specified filename.
The following code retrieves an image and saves it to a local folder. A jpg file is indeed saved to local disk, with around 40KB filesize (seems correct). When I put the local path in an img tag, the file does not display.
Firebug > Inspect Element shows a size of 0 X 0 and I'm unable to view the image when saved to my desktop.
file_put_contents, file_get_contents and getimagesize don't return FAILs. $url IS a valid image. The problem is just saving it locally, the file seems to be corrupt - how come?
$url = $image->request_url; //the image generated on the remote server
//print_r(getimagesize($url)); die;
$img = 'thumbalizr/cache/screenshot_' . $row['id'] . '.jpg'; //path to our local cache folder + unique filename
if( !$captured_file = file_get_contents($url) ) die('file could not be retrieved');
elseif( !file_put_contents($img, $captured_file, FILE_APPEND) ) die('file could not be written to local disk'); //write the image to our local cache
"Are you sure the path is correct? Have you tried an absolute path?" YES
"Have you checked that the image is downloaded correctly, perhaps with another utility (e.g. ftp, diff)?" I can download the img via ftp but it does not open on my local computer either.
"What do you get if you call the URL directly in the browser?" FF just prints out the URL instead of showing the image
"Why are you using FILE_APPEND? if the target already exists, this writes to the end, which will naturally give you a corrupt image" I removed FILE_APPEND, no difference
"source and final extension are the same?" Yes I tried with jpg, jpeg and png - no difference
"First of all, example code is wrong. Can't use $capture_file in file_put_content because that variable is not defied becouso of if else if block logic." - WRONG, that code does run!
"Can you look into the image file" - no! Although the file has a realistic file size and I can download it, it's impossible to open it.
First off check the files you're been downloading in a text editor to see if you're getting HTML error pages instead of binary image data.
Second, I would use curl for this as it provides better success/error information. Here's your example modified to use it.
//path to our local cache folder + unique filename
$img_path = 'thumbalizr/cache/screenshot_' . $row['id'] . '.jpg';
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $image->request_url);
curl_setopt($c, CURLOPT_HEADER, 0);
curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($c, CURLOPT_AUTOREFERER, true);
curl_setopt($c, CURLOPT_BINARYTRANSFER, true);
curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($c, CURLOPT_FORBID_REUSE, true);
// curl can automatically write the file out for you
curl_setopt($c, CURLOPT_FILE, $img_path);
// You can get more elaborate success/error info from
// curl_getinfo() http://www.php.net/manual/en/function.curl-getinfo.php
if (!curl_exec($c)) {
die('file could not be retrieved');
}
i am developing a test/learning app. i wonder how can i test if an image from another site/domain ... i broke up my validation logic to the following
exists
is an image
is of valid type
is of a specific dimensions
is below a max size - say i want the image to load quickly. tho the hosting resource is not mine.
getimagesize() can do all but the last of your points. For that you can use filesize(). For filesize() you'll have to actually download it though, but seeing as getimagesize() also requires that, you can just save it to a temporary file. You can use tempnam() to get a temporary file that doesn't conflict with others.
checking if url exists:
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, TRUE);
$response = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if($status == 404) {//return true or whatever}
is an image, is of valid type:
determine if the file extension is valid, for example using
preg_match('/(jp[e]?g|png|gif|etc...)$/i', $url);
is of specific dimensions:
use GD to create a resource and then check size by getImageSize($resource)
is below max size:
in addition to step 1 - $size = curl_getinfo($handle, CURLINFO_SIZE_DOWNLOAD);
Remember that you must have cURL and GD enabled.