cURL script will not download images; Instead renders junk - php

I have been using the following function to download pictures from a distributor for use on our website as was described here:
$url = "http://covers.stl-distribution.com/7819/lg-9781936417445.jpg";
$itemnum = 80848;
$path = "www.gullions.com/localstore/test/test.jpg";
header('Content-type: image/jpeg');
$ch = curl_init($url);
$fp = fopen("http://www.gullions.com/localstore/test/test.jpg", 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
fclose($fp);
Instead of downloading and saving the picture, it only prints crazy characters to the screen. I know that means that for some reason the browser is trying to render the picture but most likely doesn't recognize the file type. But I can't seem to find the problem. You can see the crazy output by navigating here. To verify that the image wasn't downloaded and saved, you can navigate here. Also, FTP also shows that no file was downloaded. If you navigate to the original picture's download url you'll see that the file we are trying to download does in fact exist.
I have contacted my host and verified that no settings have been changed with the server, that cURL is functioning properly, and have even rolled back my browser to verify that a recent update didn't cause the issue. I created a test file by removing the function from the application and have tried running it separately but have only had the same results.

Add:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
as by default this parameter is false. Docs read:
TRUE to return the transfer as a string of the return value of
curl_exec() instead of outputting it out directly.
EDIT
Setting CURLOPT_RETURNTRANSFER make curl_exec() return data, so it should be written manually, like this:
$url = "http://covers.stl-distribution.com/7819/lg-9781936417445.jpg";
$ch = curl_init($url);
$fp = fopen("./test.jpg", 'wb');
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch, CURLOPT_HEADER, 0);
fwrite($fp, curl_exec($ch));
curl_close($ch);
fclose($fp);
Also this code, that uses CURLOPT_FILE works for me just fine:
$url = "http://covers.stl-distribution.com/7819/lg-9781936417445.jpg";
$ch = curl_init($url);
$fp = fopen("./test.jpg", 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
so I basically suspect that your file handle is not valid, therefore cURL falls back to default output. Try this code with elementary error checking (you should ALWAYS check for errors):
$url = "http://covers.stl-distribution.com/7819/lg-9781936417445.jpg";
$fp = fopen("./test.jpg", 'wb');
if( $fp != null ) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
} else {
exit('ERROR: Failed to open file');
}
Note that my examples write to the same folder scripts sits in. It must work unless your server got file permissions messed badly. If it works for you, then investigate if (usually) user your scripts runs as can write to your target folder.

You haven't told your browser what type of file to expect, so it's probably defaulting to text/plain.
You need at least:
header('Content-type: image/jpeg');
As well, curl by default outputs whatever it fetches, unless you explicitly tell it you want to have the fetched data returned, or saved directly to file.

Related

Download image using PHP but image is htaccess redirected?

I want to download an image to my server using PHP. This image's html only allows target="_self" meaning it can only be downloaded from the browser apparently. I try to access the image directly in the browser and I get redirected. Is there any way to download this image onto my server via PHP? Maybe I'm missing an option in cURL?
Thanks!
Yes, you have to tell CURL to follow redirects --- try this function:
function wgetImg($img, $pathToSaveTo) {
$ch = curl_init($img);
$fp = fopen($pathToSaveTo, 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}

How to ensure download does not breaks using PHP Curl

I have using PHP's Curl function to download a list of pdfs from the backend. But sometimes some pdfs are corrupted.
I think, this happens because the downloads breaks and it will start to download the next pdf before completing the previous download.
Any idea how to prevent this? I am using the code below:
function downloadAndSave($urlS,$pathS)
{
$fp = fopen($pathS, 'w');
$ch = curl_init();
curl_setopt($ch,CURLOPT_PROXY,"http://test:1234");
curl_setopt($ch,CURLOPT_PROXYPORT,1234);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($ch,CURLOPT_URL,$urlS);
curl_setopt($ch, CURLOPT_FILE, $fp);
$data = curl_exec($ch);
fclose($fp);
}
I have tried using CURLOPT_CONNECTTIMEOUT but no difference. Any other way to prevent this?

Can I use a URL as the source for imagecreatefromjpeg() without enabling fopen wrappers?

I know it’s possible to use imagecreatefromjpeg(), imagecreatefrompng(), etc. with a URL as the ‘filename’ with fopen(), but I'm unable to enable the wrappers due to security issues. Is there a way to pass a URL to imagecreatefromX() without enabling them?
I’ve also tried using cURL, and that too is giving me problems:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://www.../image31.jpg"); //Actually complete URL to image
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
$image = imagecreatefromstring($data);
var_dump($image);
imagepng($image);
imagedestroy($image);
You can download the file using cURL then pipe the result into imagecreatefromstring.
Example:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $imageurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // good edit, thanks!
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); // also, this seems wise considering output is image.
$data = curl_exec($ch);
curl_close($ch);
$image = imagecreatefromstring($data);
You could even implement a cURL based stream wrapper for 'http' using stream_wrapper_register.
You could always download the image (e.g. with cURL) to a temporary file, and then load the image from that file.

File download PHP script doesn't work because of server delay

I have this code to download a file, but on sourceforge.net sever there is a 5 seconds delay before file starts to download (You can see it if you try to load this link in browser). And I have file with zero size after script is done. How can I download this file? Thanx in advance!
$url = 'http://downloads.sourceforge.net/project/gnucash/gnucash%20%28stable%29/2.4.9/gnucash-2.4.9-setup.exe';
$ch = curl_init($url);
$fp = fopen('/home/content/11/8564211/html/'.substr($url,strrpos($url,'/'),strlen($url)), 'w');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
Sourceforge uses a meta refresh tag to start the download and because CURLOPT_FOLLOWLOCATION responds to Location: header it will most likely not help.
I think you're going to have to do som HTML parsing to achieve what you want to do. You have to find this line:
<meta http-equiv="refresh" content="5; url=http://downloads.sourceforge.net/project/gnucash/gnucash%20%28stable%29/2.4.9/gnucash-2.4.9-setup.exe?r=&ts=1333621946&use_mirror=switch">
Then you must get the url from the line and load that.
It's possible that Sourceforge uses some cookie or session based stopper for this kind of downloads so you may have to compensate for that.
I haven't tested this but it looks like this is close to the way you have to do this.
You can try this:
$url = 'http://downloads.sourceforge.net/project/gnucash/gnucash%20%28stable%29/2.4.9/gnucash-2.4.9-setup.exe';
$ch = curl_init($url);
$fp = fopen('/home/content/11/8564211/html/'.substr($url,strrpos($url,'/'),strlen($url)), 'w');
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
fclose($fp);
To avoid timeouts in PHP you can use:
set_time_limit($hugetimeout);
before your script. You can read further documentation here.
On the download page, there's a direct link, you could try using that instead ?

capturing curl stdout into variable in PHP

Task
Downloading binary files from a remote media processing server to a web server.
This works but I cannot capture the curl stdout output
$result = shell_exec('curl -v http://domain.com/images/dir/dir/dir/file.jpg --user username:password -o /usr/www/htdocs/images/dir/dir/dir/file.jpg');
Note:
I have had no luck using the PHP curl wrapper methods for this task, partly because I've never used PHP curl wrappers for FTP downloads.
Question
Can someone explain how to capture the output from the command that I am shelling out to or a simple example using PHP curl wrappers?
Here is what I tried and the part I'm stumped on is how to get the new file placed on the target server - The line that's wrong is the CURLOPT_FILE line. I don't want to have to create a stub file, open it and then write to it.
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $ftpserver.$file['directory'].$filename); #input
curl_setopt($curl, CURLOPT_FILE, $dest); #output
curl_setopt($curl, CURLOPT_USERPWD, "$user:$password");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
Thanks
According to a comment in the PHP manual, you must be sure to close your curl stream AND your file handler before the file is written properly. I'll copy the example here for search purposes:
<?php
$fh = fopen('/tmp/foo', 'w');
$ch = curl_init('http://example.com/foo');
curl_setopt($ch, CURLOPT_FILE, $fh);
curl_exec($ch);
curl_close($ch);
# at this point your file is not complete and corrupted
fclose($fh);
# now you can use your file;
read_file('/tmp/foo');
?>
Also, I would debate the merits of using CURLOPT_RETURNTRANSFER with CURLOPT_FILE, as CURLOPT_RETURNTRANSFER tells curl to return the fetched results as the result of curl_exec(). You probably don't need that if you're just writing it to a file.
$dest needs to be a file resource opened via
$dest = fopen("filename.ext", "w");
does that work for you?
This fixed it by redirecting stdout output: 2>&1
So this works:
$result = shell_exec('curl -v http://domain.com/images/dir/dir/dir/file.jpg --user username:password -o /usr/www/htdocs/images/dir/dir/dir/file.jpg 2>&1');
It would be great to be able to use the PHP curl wrappers but not if it means opening a stub file on the source machine and then writing to it. The curl command line version just moves over the file, nice and neat. If anyone knows how to do what I'm trying to do using PHP wrappers, I'd love to see how you do it.
/**
*Downloads a binary file into a string
*#param string $file URL's file
*#param string $ref Referer
*#return string $downloaded_binary string containing the binary file
*/
function download_file($file, $ref)
{
$curl_obj = curl_init();
curl_setopt($curl_obj, CURLOPT_URL, $file);
curl_setopt($curl_obj, CURLOPT_REFERER, $ref);
curl_setopt($curl_obj, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($curl_obj, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl_obj, CURLOPT_MAXREDIRS, SPDR_MAX_REDIR);
curl_setopt($curl_obj, CURLOPT_FOLLOWLOCATION, TRUE); //followlocation cannot be used when safe_mode/open_basedir are on
curl_setopt($curl_obj, CURLOPT_SSL_VERIFYPEER, FALSE);
$downloaded_binary = curl_exec($curl_obj);
curl_close($curl_obj);
return $downloaded_binary;
}
I think the way to do this is with ob_start().
ob_start();
curl_exec($curl);
$result = ob_get_clean();

Categories