PHP: How to Download a Remote Image using GD or cURL

Posted on January 5, 2009, under PHP,  Bookmark it

This a PHP Class useful if you need to download images from a remote location. You can choose between 2 methods to retrieve the image: using GD or cURL.

Here is the class (I will explain you how it works below):

<?php
class GetImage {

var $source;
var $save_to;
var $set_extension;
var $quality;

function download($method = 'curl') // default method: cURL
{
$info = @GetImageSize($this->source);
$mime = $info['mime'];

// What sort of image?
$type = substr(strrchr($mime, '/'), 1);

switch ($type)
{
case 'jpeg':
    $image_create_func = 'ImageCreateFromJPEG';
    $image_save_func = 'ImageJPEG';
	$new_image_ext = 'jpg';

	// Best Quality: 100
	$quality = isSet($this->quality) ? $this->quality : 100;
    break;

case 'png':
    $image_create_func = 'ImageCreateFromPNG';
    $image_save_func = 'ImagePNG';
	$new_image_ext = 'png';

	// Compression Level: from 0  (no compression) to 9
	$quality = isSet($this->quality) ? $this->quality : 0;
    break;

case 'bmp':
    $image_create_func = 'ImageCreateFromBMP';
    $image_save_func = 'ImageBMP';
	$new_image_ext = 'bmp';
    break;

case 'gif':
    $image_create_func = 'ImageCreateFromGIF';
    $image_save_func = 'ImageGIF';
	$new_image_ext = 'gif';
    break;

case 'vnd.wap.wbmp':
    $image_create_func = 'ImageCreateFromWBMP';
    $image_save_func = 'ImageWBMP';
	$new_image_ext = 'bmp';
    break;

case 'xbm':
    $image_create_func = 'ImageCreateFromXBM';
    $image_save_func = 'ImageXBM';
	$new_image_ext = 'xbm';
    break;

default:
	$image_create_func = 'ImageCreateFromJPEG';
    $image_save_func = 'ImageJPEG';
	$new_image_ext = 'jpg';
}

if(isSet($this->set_extension))
{
$ext = strrchr($this->source, ".");
$strlen = strlen($ext);
$new_name = basename(substr($this->source, 0, -$strlen)).'.'.$new_image_ext;
}
else
{
$new_name = basename($this->source);
}

$save_to = $this->save_to.$new_name;

    if($method == 'curl')
	{
    $save_image = $this->LoadImageCURL($save_to);
	}
	elseif($method == 'gd')
	{
	$img = $image_create_func($this->source);

	    if(isSet($quality))
	    {
		   $save_image = $image_save_func($img, $save_to, $quality);
		}
		else
		{
		   $save_image = $image_save_func($img, $save_to);
		}
	}

	return $save_image;
}

function LoadImageCURL($save_to)
{
$ch = curl_init($this->source);
$fp = fopen($save_to, "wb");

// set URL and other appropriate options
$options = array(CURLOPT_FILE => $fp,
                 CURLOPT_HEADER => 0,
                 CURLOPT_FOLLOWLOCATION => 1,
	             CURLOPT_TIMEOUT => 60); // 1 minute timeout (should be enough)

curl_setopt_array($ch, $options);

curl_exec($ch);
curl_close($ch);
fclose($fp);
}
}
?>

Variables Info

var $source – The URL to the image (ex: http://www.domain.com/images/logo.jpg).

var $save_to – The path to the folder where the image will be saved (with trailing slash at the end)

var $set_extension – Are there any cases when the images you’re downloading have a wrong extension or do not have an extension at all? Consider turning this to “true”. Based on the mime type of the image, an extension is automatically assigned to the file.

var $quality – This is the 3rd argument that is passed to the image saver function. It is used for JPEG (from 0 to 100) or PNG (from 0 to 9) images.

How it works?

After initializing the class and the necessary variables are set, download() is called. Here the GetImageSize() function is used to obtain information regarding the image. We are interested in the mime-type from which he have to extract the type of image. Based on $type we will set some variables such: $image_create_func, $image_save_func, $new_image_ext (useful if $set_extension is set to ‘true’) and even $quality for ‘JPEG’ and ‘PNG’. The first 2 variables are needed in case we will use GD to download the image.

If $this->set_extension is not set, the saved image will have exactly the same name and extension (if any) as the remote image. If it is set, then we add $new_image_ext to the file name (could be the same as the remote one):

if(isSet($this->set_extension))
{
$ext = strrchr($this->source, ".");
$strlen = strlen($ext);
$new_name = basename(substr($this->source, 0, -$strlen)).'.'.$new_image_ext;
}
else
{
$new_name = basename($this->source);
}

Set the full path where the image will be saved (filename + save folder):

$save_to = $this->save_to.$new_name;

Now, some functions would be called based on the $method value (could be ‘gd or ‘curl’):

   if($method == 'curl')
	{
    $save_image = $this->LoadImageCURL($save_to);
	}
	elseif($method == 'gd')
	{
	$img = $image_create_func($this->source);

	    if(isSet($quality))
	    {
		   $save_image = $image_save_func($img, $save_to, $quality);
		}
		else
		{
		   $save_image = $image_save_func($img, $save_to);
		}
	}

If we choose ‘gd’ the LoadImageCURL() function will be called with one argument, $save_to, representing the full path where the image would be saved.

The curl_unit() is called with the ‘url’ argument ($this->source). The session is initialized and returns a cURL handle for use with curl_setopt_array(), curl_exec() and curl_close() functions. The next thing to do is to open the remote image for writing using fopen():

$ch = curl_init($this->source);
$fp = fopen($save_to, "wb");

The function curl_setopt_array() sets multiple options for a cURL transfer without repetitively calling curl_setopt():

// set URL and other appropriate options
$options = array(CURLOPT_FILE => $fp,
                 CURLOPT_HEADER => 0,
                 CURLOPT_FOLLOWLOCATION => 1,
	             CURLOPT_TIMEOUT => 60); // 1 minute timeout (should be enough)

curl_setopt_array($ch, $options);

Now we need to grab the URL and pass it to the browser:

curl_exec($ch);

The last things to do is closing both the cURL resource (to free up system resources) and the open file pointer:

curl_close($ch);
fclose($fp);

The image is now saved in the specified folder.

Now, let’s see how we can download the image using the ‘gd’ method! We’ll call the function needed to create the image from URL ($image_create_func). It’s used to return an image identifier representing the image obtained from the given URL:

// possible values: ImageCreateFromJPEG, ImageCreateFromPNG etc.
$img = $image_create_func($this->source);

The next function used ($image_save_func) is used to create the image from the given image ($img). Another aspect here is the $quality variable. For JPEG images, the value ranges from 0 (worst quality, smaller file) to 100 (best quality). The default is the default IJG quality value (about 75). As for the PNG images, the range is from 0 (no compression) to 9.

if(isSet($quality))
{
// possible values: ImageJPEG, ImagePNG etc.
$save_image = $image_save_func($img, $save_to, $quality);
}
else
{
$save_image = $image_save_func($img, $save_to);
}

Here’s an example of how you can use this class:

<?php
include_once 'class.get.image.php';

// initialize the class
$image = new GetImage;
$image->source = 'http://l.yimg.com/a/i/ww/beta/y3.gif';
$image->save_to = 'images/'; // with trailing slash at the end

$get = $image->download('gd'); // using GD

if($get)
{
echo 'The image has been saved.';
}
?>

NOTE: Make sure the folder where the image will be saved is writable (chmod 0777).

Happy coding!

"Subscribe to the blog"
Receive an update straight to your inbox every time I publish a new article. Your email address will never be shared

Related Posts

33 Replies to "PHP: How to Download a Remote Image using GD or cURL"

  1. Great! Excellent piece of code. I was going to write it myself but this saves al lot of time.

  2. i get “Could not obtain mime-type information. Make sure that the remote file is actually a valid image” error always. :(

    1. This error appears only if the remote file hasn’t a valid image mime type or a connection to that image cannot be made. What is the address of the image that you are trying to download?

  3. guess what? i think the error was in the variable i was passing to the function, if it had an space (the image path) it couldn’t be downloaded, so, i used str_replace(‘ ‘, ‘%20′, $imageURL) and it worked.

    i did a very nice osC database leecher, even with images.

    thanks to you!

  4. class works great! thanks.

  5. First off, tx for the class.

    Secondly, i have a bit of a problem/question

    I have altered your class a tiny bit

    if(isSet($this->givenName)) {
    $new_name = $this->givenName.’.’.$new_image_ext;
    }

    if(!isSet($this->givenName)) {
    if(isSet($this->set_extension))
    {

    }
    so ik can use a customize name.

    When i hardcod the name it works like
    $image = new GetImage;
    // just an image URL
    $image->source = ‘http://img.dailymail.co.uk/i/pix/2007/12_01/17banksyES_468x606.jpg’;
    $image->givenName = “testing”;

    but when i set it dynamic it doesn’t work anymore, like
    $image = new GetImage;
    // just an image URL
    $image->source = ‘http://img.dailymail.co.uk/i/pix/2007/12_01/17banksyES_468x606.jpg’;
    $test = $merchantName.’-’.$this->id;
    $image->givenName = $test;

    The problem is i don’t get the file with an extension?

    regards

  6. cool, I plan to write something like this, so nice one.

  7. Gabriel,

    I have a few questions about use of this for a non-profit moving images from hosting. If you would please email me – I am unable to find an email address for you.

  8. Call to undefined function curl_init()
    what wrong?
    by the way, i using php5

    1. You do not have the cURL library enabled/installed. Check these URLs: http://www.php.net/manual/en/curl.setup.php and http://www.php.net/manual/en/curl.installation.php (especially the comments).

  9. john, are you sure you have enabled curl in php.ini ?

  10. Just want to point out that by using @GetImageSize(), this class will automatically fail on websites that require you to fake the referer before downloading an image. Perhaps the next version could use cURL to determine the MIME type and allow for passing cURL OPTS to the function. Thanks for the awesome start though.

  11. GREAT! but, how can i get the path to image in their new folder?

    can u help me with this?

    :)

    1. Yeah, I’m looking for the same thing :)

  12. Thank you very much! this script is awesome!!!

    just need to combination with another GD script to rename the file, automatic create thumbnail and also automatic create folder based on the image category… :)

  13. Hi,
    I need to pull down some images that work fine via a browser but when using code like this or even WGET, I get ‘connection refused’. Any ideas on how to get these images?
    Cheers.

  14. I also get ‘connection refused’ with getimagesize and can’t find a solution anywhere.

  15. code works great! thanks.

  16. Gabriel, the code works great. However, I was wondering how I would go about overwriting an image rather than saving a new one.. Didn’t see any options for that in the class.

    Thanks,

    Arthur

  17. Hi, first off – very nice class!

    I’ve been trying it out and have sorted through most of the little problems with less then stellar data I’ve received, but I am now having a problem in some cases where I get

    Fatal error: Call to undefined method GetImage::LoadImageCURL()

    It has worked fine to download many images, but is stopping on a few. I checked and the save path and the image path are all valid and working images.

    Ideas as to what to look for/test?

  18. Hi,

    What should I do if I have an abstract URL like:

    http://example.com/apps/1196/

    where the file is located under 1196 folder and the service is having internal interpretation of the file re-routing.

    As a user of this service I can not see the actual name of the file and my application does not have any UI client..Ideally it is a service-to-service calling.

    The file name could be x.apk and I want to get the file downloaded with the same name on my server…….

    Thanks in advance.

  19. Got around the fatal error. Here are a couple tweaks I made that might be useful to others.

    1) I didn’t want the script to STOP when it failed to get an image, but instead to just skip over and continue on to the next in the list.

    I changed this line
    if(!$mime) exit('Could not obtain mime-type information. Make sure that the remote file is actually a valid image.');

    to

    if(!$mime) {
    $empty_image = "empty.jpg";
    return $empty_image;
    }
    else {

    and then added } before the line “function LoadImageCURL($save_to);

    I also had a problem with the server having images with spaces in the file name. Well, feeding in %20 as another poster suggested worked well, but I didn’t want to save the file names with a %20 in it as I then had a problem on my server.

    So looking to this section:

    if(isSet($this->set_extension))
    {
    $ext = strrchr($this->source, ".");
    $strlen = strlen($ext);
    $new_name = basename(substr($this->source, 0, -$strlen)).'.'.$new_image_ext;
    }
    else
    {
    $new_name = basename($this->source);
    }

    I changed it to:

    if(isSet($this->set_extension))
    {
    $ext = strrchr($this->source, ".");
    $strlen = strlen($ext);
    $new_name = basename(substr($this->source, 0, -$strlen)).'.'.$new_image_ext;
    $new_name = str_replace('%20', '_', $new_name);
    }
    else
    {
    $new_name = basename($this->source);
    $new_name = str_replace('%20', '_', $new_name);
    }

    Basically replacing the %20 with an _ and then returning that new name back as well.

    Hope this helps someone else.

  20. good method. I’m using gd method, it’s work ((: Thank you bitrepository.com team..

  21. thanks paul for solution I have the same problem Could not obtain mime-type information. Make sure that the remote file is actually a valid image.

  22. how do use this script for grab or just linking image from mangareader,mangashare,etc. with automatic scrape/grab

  23. Thanks the code works great.

    However, I wrote my own code before I found this page and I’m having the exact same problem with both sets of code.

    I’m copying about 2,500 images and the images are coming across and it looks like the right size but the local images are not accessible. When I do a “ls -l *” all the files have ?? at the end of the filename, i.e filename.jpg??.

    The directory I’m copying to has 777 permissions. I’m at a total lost.

    Any ideas?

  24. Great code! Amazing! I have a question though. I modified the code, so that it’s in a for loop 200 times. each time URL value is image$i so i want it to get 200 images. it works for about 19, then it says timeout or session took longer than 30 seconds, etc, etc. I modified my php.ini in php and apache directories to 300 (i believe 300 seconds is reasonable) and it still wont save more than 25 but now with no errors D:

  25. Nevermind XD set_time_limit (300); does wonders~

  26. any one can tell me how to get all image of a web page.
    i want to pull the picture gallery of website. how can i do ?

  27. Hello.
    First I would like to say that it’s wery nice of you to share your knowledge with others.
    You have created wonderful tutorial.
    I have some problems with this script:
    1. I was getting ‘Could not obtain mime-type information’ message so I commented line:

    //if(!$mime) exit(‘Could not obtain mime-type information. Make sure that the remote file is actually a valid image.’);
    and I have added another line:

    $type = ‘jpeg’;

    This way I get the image from my XAMPP local web server, but not on my real web server http://amicus.ba

    If I start script on my real web server, i do not receive message: ‘The image has been saved.’ and I and up with image size 0KB.

    How do I fix that?

    2. Can I rename image dinamically (date and time in the name) so I can keep all saved images?

    Thanx in advance.

  28. To be more specific, I want to take pictures from public web cam (http://195.222.51.21:8080/cam_1.jpg) every hour and later to create time laps video so everione can see how this square in my town is changing.

    This script is working on my localhost but not on my real web server.

    I do not receive any error (beside ‘Could not obtain mime-type information’ but I solved that)

    I would be so gatefull if you can help me with this.

  29. Great code, saved me from an endless loop of misery with gd

Leave a Reply


* = required fields

  (will not be published)


XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Note: If you want to post CODE Snippets, please make them postable first!
(e.g. <br /> should be converted to &lt;br /&gt;)