Save a remote image on my server...

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
is_blank
Forum Commoner
Posts: 36
Joined: Sat Jun 25, 2005 6:05 pm
Location: Tennessee, USA

Save a remote image on my server...

Post by is_blank »

Hello! I'm a first-time poster, and (relative) PHP newbie. I've got a web site I run for my high school students, and I'm looking for a way to reproduce the Wikipedia picture of the day in a sidebar on my front page. (I believe, with proper links back, etc. that should be ok, under fair use and GPL, yes?)

I can handle all of the grabbing and parsing necessary, but I'd like to temporarily store the image on my server, so I can shrink it with imagemagick (they need to be 188px wide). That picture will then link back to the Wikipedia page.

So the plan is to grab the image (once a day, only; I'll run the script as a cron job), and save it to my own directory with a filename like 'potd.jpg' and then overwrite it the next day with the new image.

I've already got a script that grabs the image url; they look something like: http://upload.wikimedia.org/wikipedia/c ... ager_1.jpg

So what's the best way to simply save that image as potd.jpg on my server? Can it be done?
User avatar
nigma
DevNet Resident
Posts: 1094
Joined: Sat Jan 25, 2003 1:49 am

Post by nigma »

I'd use fopen to open two streams -- one for reading the remote image, one for writing it locally -- and then use fread & fwrite to copy the image.

Look something like:

Code: Select all

$remoteCopy = fopen(REMOTE_PATH,'rb'); // open remote image for reading in binary mode
$localCopy  = fopen(LOCAL_PATH,'wb');  // open/create local file for writing in binary mode

// put the contents of $remoteCopy in $localCopy
fwrite($localCopy, fread($remoteCopy,filesize($remoteCopy)));

// close both streams
fclose($remoteCopy);
fclose($localCopy);
Untested, but regardless of what the working version looks like the logic here will hold true.
Last edited by nigma on Sat Jun 25, 2005 9:40 pm, edited 1 time in total.
User avatar
is_blank
Forum Commoner
Posts: 36
Joined: Sat Jun 25, 2005 6:05 pm
Location: Tennessee, USA

Post by is_blank »

Hm. I'm gettting some errors I don't understand. First of all, for simplicity's sake, I hardcoded some values:

Code: Select all

$remoteCopy = fopen('http://upload.wikimedia.org/wikipedia/commons/thumb/0/04/300px-Jupiter_from_Voyager_1.jpg','rb'); // open remote image for reading in binary mode
$localCopy  = fopen('potd.jpg','wb');  // open/create local file for writing in binary mode
 
// put the contents of $remoteCopy in $localCopy
fwrite($localCopy, fread($remoteCopy,filesize($remoteCopy)));
 
// close both streams
fclose($remoteCopy);
fclose($localCopy);
That's giving me the following errors:

Code: Select all

Warning: filesize(): Stat failed for Resource id #5 (errno=2 - No such file or directory) in /home/ferrellw/public_html/php/picotd.php on line 49

Warning: fread(): Length parameter must be greater than 0. in /home/ferrellw/public_html/php/picotd.php on line 49
Line 49 is the fwrite() line. Is it not able to read the remote file?
User avatar
nigma
DevNet Resident
Posts: 1094
Joined: Sat Jan 25, 2003 1:49 am

Post by nigma »

Here's a function you can use in place of filesize() that will work with remote files:

Code: Select all

function remoteFilesize($fp) {
  $temp = &quote;&quote;;
  while (!feof($fp)) $temp .= fread($fp,1024);
  return strlen($temp);
}
Once you've got that function in your code all you have to do is change the second argument of fread to call remoteFilesize() instead of filesize().
Last edited by nigma on Sat Jun 25, 2005 9:38 pm, edited 1 time in total.
User avatar
is_blank
Forum Commoner
Posts: 36
Joined: Sat Jun 25, 2005 6:05 pm
Location: Tennessee, USA

Post by is_blank »

Wow. Thanks for all your help! It's not complaining anymore, but it's creating a file called picotd.jpg that's 0 bytes. I'm not sure what I should check next. I see what everything's doing--where could the hole be?
User avatar
nigma
DevNet Resident
Posts: 1094
Joined: Sat Jan 25, 2003 1:49 am

Post by nigma »

:oops: The following will work. Sorry about previous.

Code: Select all

<?php
$remoteCopy = fopen('http://upload.wikimedia.org/wikipedia/commons/thumb/0/04/300px-Jupiter_from_Voyager_1.jpg','rb'); // open remote image for reading in binary mode
$localCopy  = fopen('potd.jpg','wb');  // open/create local file for writing in binary mode
 
// put the contents of $remoteCopy in $localCopy
while (!feof($remoteCopy)) {
	fwrite($localCopy, fread($remoteCopy, 8192));
}
 
// close both streams
fclose($remoteCopy);
fclose($localCopy);
?>
User avatar
is_blank
Forum Commoner
Posts: 36
Joined: Sat Jun 25, 2005 6:05 pm
Location: Tennessee, USA

Post by is_blank »

Beautiful! That does the trick! No need for :oops:; you saved me hours of :x!

One question: why "fread($remoteCopy, 8192));"? Do I really want "fread($remoteCopy, remoteFilesize($remoteCopy))" there, or is there a reason for 8192?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

is_blank wrote:Beautiful! That does the trick! No need for :oops:; you saved me hours of :x!

One question: why "fread($remoteCopy, 8192));"? Do I really want "fread($remoteCopy, remoteFilesize($remoteCopy))" there, or is there a reason for 8192?
Not sure on the 8192 but I do know that you can cut out alot of that hassle with the nice handy file_get_contents() function ;) - it does all that for you (I assume).

Code: Select all

function downloadFile($remote, $local) {

    if($data = @file_get_contents($remote)) { //Supress error and write our own
        $handle = fopen($local, 'w');
        if (fwrite($handle, $data)) {
            fclose($handle);
            return true;
        } else {
            fclose($handle);
            echo 'Local file '.$local.' could not be written. Check the permissions.';
            return false;
        }
    } else {
        echo 'Remote file '.$remote.' could not be found. Some servers reject request without a browser type.';
        return false;
    }

}
Which is quite simply:

Code: Select all

$data = file_get_contents($remote_file);
$handle = fopen($local_file, 'w');
fwrite($handle, $data);
fclose($handle);
With a bit more error checking. Same thing anyway... just a bit easier ;)
User avatar
is_blank
Forum Commoner
Posts: 36
Joined: Sat Jun 25, 2005 6:05 pm
Location: Tennessee, USA

Post by is_blank »

Thanks, as well. Very nice. It's helpful to see all this stuff strung together! :wink:
Post Reply