440

I need to save an image from a PHP URL to my PC. Let's say I have a page, http://example.com/image.php, holding a single "flower" image, nothing else. How can I save this image from the URL with a new name (using PHP)?

Foreever
  • 7,099
  • 8
  • 53
  • 55
riad
  • 7,144
  • 22
  • 59
  • 70
  • 1
    If copying a large quantity or size of files, note that **CURL** methods are preferable (like the 2nd example in the [accepted answer](https://stackoverflow.com/a/724449/8112776)) as **CURL** takes about a third of the time as `file_put_contents` etc. – ashleedawg May 12 '19 at 11:34

11 Answers11

776

If you have allow_url_fopen set to true:

$url = 'http://example.com/image.php';
$img = '/my/folder/flower.gif';
file_put_contents($img, file_get_contents($url));

Else use cURL:

$ch = curl_init('http://example.com/image.php');
$fp = fopen('/my/folder/flower.gif', 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
Andrew
  • 227,796
  • 193
  • 515
  • 708
vartec
  • 131,205
  • 36
  • 218
  • 244
  • 1
    Thanks bro, your code help me to solve the problem. But could u pls help me to make the script automated .I mean when a new gif image come to the url (“http://example.com/image.php”) then our script automatically fetch the new image and store it to my directory? – riad Apr 07 '09 at 08:26
  • 38
    And how do you know, that the new image "came"? – vartec Apr 07 '09 at 08:37
  • 2
    I think riad means using a `$_GET` variable containing the URL of the image `http://example.com/fetch-image.php?url=http://blabla.com/flower.jpg`. In the case of this example, you could just call `$_GET['url']` in your PHP script, like so: `$ch = curl_init($_GET['url']);`. – Mathias Bynens Nov 29 '09 at 13:04
  • I'm curious, if the type of image being generated by the php varies, can you dynamically set the saved image type? How do you tell the type of the generated image? – andrew Jan 18 '11 at 21:23
  • 6
    +1 for being the only answer I've seen that includes the "b" for binary flag. – Will Morgan Oct 17 '12 at 16:12
  • 46
    @vartec: coz it was smoking a cigarette and had a big smile on its face :) – Jimbo May 27 '13 at 20:22
  • 1
    Could you expand on this so that there is a way to compare images already downloaded? Let's say you've downloaded flower.gif in a previous attempt but need to run the script again, I imagine you'd need to compare filesizes - if they are the same, skip the download. – Tony M Jul 19 '13 at 14:18
  • To use this method, you have to set allow_url_fopen to on. The allow_url_fopen directive is disabled by default. You should be aware of the security implications of enabling the allow_url_fopen directive. PHP scripts that can access remote files are potentially vulnerable to arbitrary code injection. When the allow_url_fopen directive is enabled, you can write scripts that open remote files as if they are local files. – Foreever Aug 12 '14 at 06:19
  • 1
    I have used the first solution, it generates the image but image has no data. It says invalid image. Thanks – Mohan Oct 16 '15 at 07:15
  • YOU ROCK BRO THANKS. I was looking for it for weeks – karlosuccess Jan 13 '16 at 04:39
  • I have asked a simillar question [here](http://stackoverflow.com/questions/36903392/why-file-get-contents-doesnt-work-without-protocol), May you please take a look at it? – stack Apr 28 '16 at 01:34
  • 1
    @Abdukhafiz Most of Chrome's speed is from: using good protocols; creating lots of simultaneous requests; and manipulating process and operating system behaviour to give itself a (n often disproportionately) large share of the processor. – wizzwizz4 Dec 25 '16 at 10:25
  • I've been trying to code with copy($source, $target), but that was slow like dial up connection 2020. and this code is super fast. Thank you sir. – MFarooqi Aug 03 '17 at 17:18
  • can you validate that it's an image before saving the file? – Luc Laverdure Sep 22 '18 at 05:41
  • Some servers block the first method, I encourage people to use cURL method. – Marcelo Agimóvel Nov 12 '18 at 02:01
  • @vartec i have a download link like 'https://sitename/downloads/123123123123123', image could be jpg png etc. How can i save image in folder when image extension is not given in download path? – Muhammad Rohail Dec 10 '19 at 06:42
281

Use PHP's function copy():

copy('http://example.com/image.php', 'local/folder/flower.jpg');

Note: this requires allow_url_fopen

reformed
  • 4,505
  • 11
  • 62
  • 88
Halil Özgür
  • 15,731
  • 6
  • 49
  • 56
  • No connection could be made because the target machine actively refused it. :( – jackkorbin Jul 26 '14 at 09:09
  • @jackkorbin is it an IP restriction or something? What happens when you try it in your browser? – Halil Özgür Jul 26 '14 at 15:35
  • 3
    if target folder doesn't exist, will it automatically created? – Monnster Jul 10 '15 at 15:00
  • 4
    @Monnster, no, it won't for normal filesystems. – Halil Özgür Jul 11 '15 at 23:43
  • Scenario: Loading a dynamically generated image from remote server to own server (which serves it to the user). If remote server does not supply the resource, it probably yields a `500 (Internal Server Error)` on your server. – Avatar May 18 '21 at 17:41
  • @Avatar if I understood you correctly and your concern is error handling, this would raise a warning, return false and not save it in case of an unsuccessful HTTP response. Of course, other variants can be more useful depending on the use case and requirements. – Halil Özgür May 19 '21 at 10:02
82
$content = file_get_contents('http://example.com/image.php');
file_put_contents('/my/folder/flower.jpg', $content);
soulmerge
  • 73,842
  • 19
  • 118
  • 155
  • The page is holding an animated gif image. A file is stored into the folder as flower.gif .But it is blank.No image show.any solution? – riad Apr 07 '09 at 07:07
  • Turn on error_reporting(E_ALL|E_STRICT) and check the return value of file_get_contents(), then you should get a reasonable error message. – soulmerge Apr 07 '09 at 07:12
  • Perhaps the site admin has forbidden outside referrals. In that case you can try stream_context_create() and set the appropriate HTTP headers. http://us2.php.net/manual/en/function.stream-context-create.php – Calvin Apr 07 '09 at 07:18
  • urlencode('http://example.com/image.php') == 'http%3A%2F%2Fexample.com%2Fimage.php', obviously not what you want. Also file is binary, proper flag needs to be set. – vartec Apr 07 '09 at 07:19
  • thanks for the urlencode() hint. As for the binary flag: That one is available in PHP 6 only. – soulmerge Apr 07 '09 at 07:23
  • Thanks all, it’s working fine now. But can anybody help me to do it automated. I mean when a new image come that URL 'http://example.com/image.php' my script will automatically fetch the image and store it to my directory? – riad Apr 07 '09 at 08:19
  • This is another question and it had been asked some days ago on SO, just try to search it. – soulmerge Apr 07 '09 at 11:58
  • 5
    Bit of an old thread... but don't forget file permissions for the directory you are saving into. Just wasted ten minutes forgetting the obvious. – Squiggs. Nov 23 '10 at 09:28
33

Vartec's answer with cURL didn't work for me. It did, with a slight improvement due to my specific problem.

e.g.,

When there is a redirect on the server (like when you are trying to save the facebook profile image) you will need following option set:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

The full solution becomes:

$ch = curl_init('http://example.com/image.php');
$fp = fopen('/my/folder/flower.gif', 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
curl_close($ch);
fclose($fp);
Community
  • 1
  • 1
stoefln
  • 14,498
  • 18
  • 79
  • 138
30

Here you go, the example saves the remote image to image.jpg.

function save_image($inPath,$outPath)
{ //Download images from remote server
    $in=    fopen($inPath, "rb");
    $out=   fopen($outPath, "wb");
    while ($chunk = fread($in,8192))
    {
        fwrite($out, $chunk, 8192);
    }
    fclose($in);
    fclose($out);
}

save_image('http://www.someimagesite.com/img.jpg','image.jpg');
Sam Becker
  • 19,231
  • 14
  • 60
  • 80
  • The guys url is http://example.com/image.php. Notice that it is a php generated image an not a simple jpeg. – andrew Jan 18 '11 at 21:14
  • 10
    How is the generation of the image or the files extension at all relevant to the question? – Sam Becker Jan 19 '11 at 10:33
  • fopen needs allow_url_fopen=1 too – zloctb Sep 18 '13 at 12:04
  • @SamThompson from the [PHP documentation](http://php.net/manual/en/function.fread.php) it means chunk size (usually 8192). – Daan Mar 02 '16 at 09:09
  • AFAIK fread may return shorter chunk than requested 8K. Don't you need to calculate effective chunk length for fwrite? – Sergey Jun 25 '18 at 16:57
10

I wasn't able to get any of the other solutions to work, but I was able to use wget:

$tempDir = '/download/file/here';
$finalDir = '/keep/file/here';
$imageUrl = 'http://www.example.com/image.jpg';

exec("cd $tempDir && wget --quiet $imageUrl");

if (!file_exists("$tempDir/image.jpg")) {
    throw new Exception('Failed while trying to download image');
}

if (rename("$tempDir/image.jpg", "$finalDir/new-image-name.jpg") === false) {
    throw new Exception('Failed while trying to move image file from temp dir to final dir');
}
Andrew
  • 227,796
  • 193
  • 515
  • 708
4

See file()PHP Manual:

$url    = 'http://mixednews.ru/wp-content/uploads/2011/10/0ed9320413f3ba172471860e77b15587.jpg';
$img    = 'miki.png';
$file   = file($url);
$result = file_put_contents($img, $file)
hakre
  • 193,403
  • 52
  • 435
  • 836
zloctb
  • 10,592
  • 8
  • 70
  • 89
4
$data = file_get_contents('http://example.com/image.php');
$img = imagecreatefromstring($data);
imagepng($img, 'test.png');
sen
  • 113
  • 8
4
$img_file='http://www.somedomain.com/someimage.jpg'

$img_file=file_get_contents($img_file);

$file_loc=$_SERVER['DOCUMENT_ROOT'].'/some_dir/test.jpg';

$file_handler=fopen($file_loc,'w');

if(fwrite($file_handler,$img_file)==false){
    echo 'error';
}

fclose($file_handler);
Joe McBride
  • 3,789
  • 2
  • 34
  • 38
karl
  • 41
  • 1
4

None of the answers here mention the fact that a URL image can be compressed (gzip), and none of them work in this case.

There are two solutions that can get you around this:

The first is to use the cURL method and set the curl_setopt CURLOPT_ENCODING, '':

// ... image validation ...

// Handle compression & redirection automatically
$ch = curl_init($image_url);
$fp = fopen($dest_path, 'wb');

curl_setopt($ch, CURLOPT_FILE, $fp);
// Exclude header data
curl_setopt($ch, CURLOPT_HEADER, 0);
// Follow redirected location
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
// Auto detect decoding of the response | identity, deflate, & gzip
curl_setopt($ch, CURLOPT_ENCODING, '');

curl_exec($ch);

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

It works, but from hundreds of tests of different images (png, jpg, ico, gif, svg), it is not the most reliable way.

What worked out best is to detect whether an image url has content encoding (e.g. gzip):

// ... image validation ...

// Fetch all headers from URL
$data = get_headers($image_url, true);

// Check if content encoding is set
$content_encoding = isset($data['Content-Encoding']) ? $data['Content-Encoding'] : null;

// Set gzip decode flag
$gzip_decode = ($content_encoding == 'gzip') ? true : false;

if ($gzip_decode)
{
    // Get contents and use gzdecode to "unzip" data
    file_put_contents($dest_path, gzdecode(file_get_contents($image_url)));
}
else
{
    // Use copy method
    copy($image_url, $dest_path);
}

For more information regarding gzdecode see this thread. So far this works fine. If there's anything that can be done better, let us know in the comments below.

Owen Far
  • 187
  • 11
1

Create a folder named images located in the path you are planning to place the php script you are about to create. Make sure it has write rights for everybody or the scripts won't work ( it won't be able to upload the files into the directory).

Ibrahim
  • 19
  • 1