Page 1 of 1

Save a remote image on my server...

Posted: Sat Jun 25, 2005 6:33 pm
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?

Posted: Sat Jun 25, 2005 6:53 pm
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.

Posted: Sat Jun 25, 2005 7:49 pm
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?

Posted: Sat Jun 25, 2005 8:34 pm
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().

Posted: Sat Jun 25, 2005 9:02 pm
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?

Posted: Sat Jun 25, 2005 9:36 pm
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);
?>

Posted: Sat Jun 25, 2005 9:54 pm
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?

Posted: Sun Jun 26, 2005 6:57 am
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 ;)

Posted: Sun Jun 26, 2005 7:51 am
by is_blank
Thanks, as well. Very nice. It's helpful to see all this stuff strung together! :wink: