Best way to download a file in PHP - php

Which would be the best way to download a file from another domain in PHP?
i.e. A zip file.

The easiest one is file_get_contents(), a more advanced way would be with cURL for example. You can store the data to your harddrive with file_put_contents().

normally, the fopen functions work for remote files too, so you could do the following to circumvent the memory limit (but it's slower than file_get_contents)
<?php
$remote = fopen("http://www.example.com/file.zip", "rb");
$local = fopen("local_name_of_file.zip", 'w');
while (!feof($remote)) {
$content = fread($remote, 8192);
fwrite($local, $content);
}
fclose($local);
fclose($remote);
?>
copied from here: http://www.php.net/fread

You may use one code line to do this:
copy(URL, destination);
This function returns TRUE on success and FALSE on failure.

Related

php - Pass contents of file to function that's expecting a filename

I have the contents of a file in a string. I need to pass this file to a function where the function is expecting the parameter to be the name of the file, not the contents. The obvious and probably simplest way to do this would be to write the contents to a temp file, then pass that file name to the function, and unlink the file once I'm finished.
However, I'm looking for a solution that doesn't involve writing the file out to the file system and then reading it back in. I've had a need for this in multiple cases, so I'm not looking for a work-around to a specific function, but more of a generic method that will work for any function expecting a file name (like file_get_contents(), for instance).
Here are some thoughts, but not sure how to pursue these yet:
Is it possible to write the contents somewhere in memory, and then
pass that to the function as a filename? Perhaps something using
php://memory.
Is it possible to write the contents to a pipe, then pass the name of the
pipe to the function?
I did a short proof-of-concept trying with php://memory as follows, but no luck:
$data = "This is some file data.\n";
file_put_contents( 'php://memory', $data );
echo file_get_contents( 'php://memory' );
Would be interested in knowing of good ways to address this. Googling hasn't come up with anything for me.
It mainly depends on what the target function does with the file name. If you're lucky, you can register your own stream wrapper:
stream_wrapper_register('demo', 'DemoStream');
$data = "This is some file data.\n";
$filename = 'demo://foo';
file_put_contents($filename, $data );
echo file_get_contents($filename);
Why not use a file in the /tmp/ directory? Like this:
<?php
$filename = '/tmp/mytmpfile';
$data = "This is some file.\n";
file_put_contents($filename, $data);
$result = file_get_contents($filename);
var_dump($result);
Well, as you say you don't want to use a file, you shouldn't use file_get_contents().
But you can achieve the same result by using stream_get_contents(), like this:
<?php
$data = "This is some file data.\n";
$handle = fopen('php://memory', 'r+'); // open an r/w handle to memory
fputs($handle, $data); // write the data
rewind($handle); // rewind the pointer
echo stream_get_contents($handle); // retrieve the contents

php file and fopen functions not working

I'm trying to learn about creating web bots and I'm working my way through a book called Webbots, Spiders, and Screen Scrapers by Michael Schrenk. In the book he gives example code for a basic bot that downloads a webpage. I have copied the code exactly as it is in the book (sans comments):
<?
$target = "http://www.schrenk.com/nostarch/webbots/hello_world.html";
$downloaded_page_array = file($target);
for($xx=0; $xx<count($downloaded_page_array); $xx++)
echo $downloaded_page_array[$xx];
?>
I put this code in a php file and uploaded to my site. When I navigate to it in the browser however, nothing happens. It just loads a blank page. No content.
Earlier I tried another snippet that the author provided, again, this one was copied EXACTLY from the book, only with this one I didn't really get a blank page, the page just tried to load until it eventually timed out. Never got the correct content back:
$target = "http://www.schrenk.com/nostarch/webbots/hello_world.html";
$file_handle = fopen($target, "r");
while (!feof($file_handle))
echo fgets($file_handle, 4096);
fclose($file_handle);
I have checked the URL to make sure the file exists and it does. I have no idea why this wouldn't work. I've read through how to use the file(); and fopen(); functions in PHP but from what I can tell they are both being used correctly. What am I doing wrong here?
Accessing URLs via fopen() is a bad idea. It requires you to have allow_url_fopen enabled in your PHP config, which opens the door to a vast number of exploits (hosters disable it for a reason).
Try using cURL functions instead: they will give you much more flexibility and control. PHP documentation gives you some great examples to start with.
Not fgets($file_handle, 4096) but fread($file_handle, 4096) ;
$target = "http://www.schrenk.com/nostarch/webbots/hello_world.html";
$file_handle = fopen($target, "r");
while (!feof($file_handle))
echo fread($file_handle, 4096);
fclose($file_handle);
Then later if you want to create a new file from the extracted text :
// extracting text operation
$target = "http://www.schrenk.com/nostarch/webbots/hello_world.html";
$file_handle = fopen($target, "r");
$getText = fread($file_handle, 4096);
fclose($file_handle);
// writing file operation
$writeHandle = fopen ("folder/text.txt","w"); // file will be created if not existed
$writeFile = fwrite($writeHandle,$getText );
fclose($writeHandle );
First you should put error_reporting(E_ALL); ini_set('display_errors', '1'); to your script to enable displaying errors in your script as AbraCadaver mentioned in his comment.
A reason could be, that allow_url_fopen is disabled on your hosting.
This option enables the URL-aware fopen wrappers that enable accessing URL object like files. Default wrappers are provided for the access of remote files using the ftp or http protocol, some extensions like zlib may register additional wrappers.
See: http://php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen
You can check that via:
var_dump(ini_get('allow_url_fopen'));
Your script requires true to run correct.
If allow_url_fopen is not true or 1 you can try to use file_get_contents() to load a url.
<?php
$homepage = file_get_contents('http://www.example.com/');
echo $homepage;
?>
See: http://php.net/manual/en/function.file-get-contents.php

Why wont my filesize() method work?

Why wont my filesize() method work? My path works for the fread() and file() methods, but it wont acknowledge the path on filesize(). Why not? What should my correct path be?
<?php
$strLessonDescription = fopen("http://nova.umuc.edu/~ct386a28/lovej2ee/exercise5/content/lesson5.txt", "r")
or die ("Error - lesson5.txt cannot be opened");
$lessonDescription = fread($strLessonDescription,
filesize("http://nova.umuc.edu/~ct386a28/lovej2ee/exercise5/content/vocabulary5.txt"));
fclose($strLessonDescription);
echo $lessonDescription;
$arrLessonVocabulary = array();
$arrLessonVocabulary = file("http://nova.umuc.edu/~ct386a28/lovej2ee/exercise5/content/vocabulary5.txt");
if (arrLessonVocabulary == NULL)
print "Error - vocabulary5.txt cannot be opened";
?>
Since the file you're trying to read is via a remote request, rather than local file, it significantly changes how you want to read that data. Per the fread() manual page, you need to read the file in chunks. Alternatively, try using file_get_contents() which should simplify your code:
$lessonDescription = file_get_contents('http://nova.umuc.edu/~ct386a28/lovej2ee/exercise5/content/vocabulary5.txt');
echo $lessonDescription;

Using a php://memory wrapper causes errors

I'm trying to extend the PHP mailer class from Worx by adding a method which allows me to add attachments using string data rather than path to the file.
I came up with something like this:
public function addAttachmentString($string, $name='', $encoding = 'base64', $type = 'application/octet-stream')
{
$path = 'php://memory/' . md5(microtime());
$file = fopen($path, 'w');
fwrite($file, $string);
fclose($file);
$this->AddAttachment($path, $name, $encoding, $type);
}
However, all I get is a PHP warning:
PHP Warning: fopen() [<a href='function.fopen'>function.fopen</a>]: Invalid php:// URL specified
There aren't any decent examples with the original documentation, but I've found a couple around the internet (including one here on SO), and my usage appears correct according to them.
Has anyone had any success with using this?
My alternative is to create a temporary file and clean up - but that will mean having to write to disc, and this function will be used as part of a large batch process and I want to avoid slow disc operations (old server) where possible. This is only a short file but has different information for each person the script emails.
It's just php://memory. For example,
<?php
$path = 'php://memory';
$h = fopen($path, "rw+");
fwrite($h, "bugabuga");
fseek($h, 0);
echo stream_get_contents($h);
yields "bugabuga".
Quickly looking at http://php.net/manual/en/wrappers.php.php and the source code, I don't see support for the "/' . md5(microtime());" bit.
Sample Code:
<?php
print "Trying with md5\n";
$path = 'php://memory/' . md5(microtime());
$file = fopen($path, 'w');
if ($file)
{
fwrite($file, "blah");
fclose($file);
}
print "done - with md5\n";
print "Trying without md5\n";
$path = 'php://memory';
$file = fopen($path, 'w');
if ($file)
{
fwrite($file, "blah");
fclose($file);
}
print "done - no md5\n";
Output:
buzzbee ~$ php test.php
Trying with md5
Warning: fopen(): Invalid php:// URL specified in test.php on line 4
Warning: fopen(php://memory/d2a0eef34dff2b8cc40bca14a761a8eb): failed to open stream: operation failed in test.php on line 4
done - with md5
Trying without md5
done - no md5
The problem here simply is the type and the syntax:
php://memory and php://temp are read-write streams that allow temporary data to be stored in a file-like wrapper. The only difference between the two is that php://memory will always store its data in memory, whereas php://temp will use a temporary file once the amount of data stored hits a predefined limit (the default is 2 MB). The location of this temporary file is determined in the same way as the sys_get_temp_dir() function.
In short, the type you want is temp instead and the syntax you want is:
php://temp/maxmemory:$limit
The $limit is in bytes. You want to count that using safe byte functions.

Whats a better way to write this function. Its gets a remote file and copys it localy, in php

So yea, im working on a windows system and while this works locally, know it will break on other peoples servers. Whats a cross platform way to do the same as this
function fetch($get,$put){
file_put_contents($put,file_get_contents($get));
}
I don't see why that would fail unless the other computer is on PHP4. What you would need to do to make that backwards compatible is add functionality to provide replacements for file_get_contents & file_put_contents:
if(version_compare(phpversion(),'5','<')) {
function file_get_contents($file) {
// mimick functionality here
}
function file_put_contents($file,$data) {
// mimick functionality here
}
}
Here would be the solution using simple file operations:
<?php
$file = "http://www.domain.com/thisisthefileiwant.zip";
$hostfile = fopen($file, 'r');
$fh = fopen("thisisthenameofthefileiwantafterdownloading.zip", 'w');
while (!feof($hostfile)) {
$output = fread($hostfile, 8192);
fwrite($fh, $output);
}
fclose($hostfile);
fclose($fh);
?>
Ensure your directory has write permissions enabled. (CHMOD)
Therefore, a replacement for your fetch($get, $put) would be:
function fetch($get, $put) {
$hostfile = fopen($get, 'r');
$fh = fopen($put, 'w');
while (!feof($hostfile)) {
$output = fread($hostfile, 8192);
fwrite($fh, $output);
}
fclose($hostfile);
fclose($fh);
}
Hope it helped! =)
Cheers,
KrX
Shawn's answer is absolute correct, the only thing is that you need to make sure your $put varialable is a valid path on either the Windows Server on the Unix server.
well when i read your question I understood you wanted to bring a file from a remote server to your server locally, this can be done with the FTP extension from php
http://www.php.net/manual/en/function.ftp-fget.php
if this is not what you intent I believe what shawn says is correct
else tell me in the comments and i'll help you more
If the fopen wrappers are not enabled, the curl extension could be: http://php.net/curl

Categories