downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Connection handling> <PUT method support
[edit] Last updated: Fri, 22 Jul 2011

view this page in

Using remote files

As long as allow_url_fopen is enabled in php.ini, you can use HTTP and FTP URLs with most of the functions that take a filename as a parameter. In addition, URLs can be used with the include(), include_once(), require() and require_once() statements (since PHP 5.2.0, allow_url_include must be enabled for these). See Supported Protocols and Wrappers for more information about the protocols supported by PHP.

Note:

In PHP 4.0.3 and older, in order to use URL wrappers, you were required to configure PHP using the configure option --enable-url-fopen-wrapper .

Note:

The Windows versions of PHP earlier than PHP 4.3 did not support remote file accessing for the following functions: include(), include_once(), require(), require_once(), and the imagecreatefromXXX functions in the GD and Image Functions extension.

For example, you can use this to open a file on a remote web server, parse the output for the data you want, and then use that data in a database query, or simply to output it in a style matching the rest of your website.

Example #1 Getting the title of a remote page

<?php
$file 
fopen ("http://www.example.com/""r");
if (!
$file) {
    echo 
"<p>Unable to open remote file.\n";
    exit;
}
while (!
feof ($file)) {
    
$line fgets ($file1024);
    
/* This only works if the title and its tags are on one line */
    
if (preg_match ("@\<title\>(.*)\</title\>@i"$line$out)) {
        
$title $out[1];
        break;
    }
}
fclose($file);
?>

You can also write to files on an FTP server (provided that you have connected as a user with the correct access rights). You can only create new files using this method; if you try to overwrite a file that already exists, the fopen() call will fail.

To connect as a user other than 'anonymous', you need to specify the username (and possibly password) within the URL, such as 'ftp://user:password@ftp.example.com/path/to/file'. (You can use the same sort of syntax to access files via HTTP when they require Basic authentication.)

Example #2 Storing data on a remote server

<?php
$file 
fopen ("ftp://ftp.example.com/incoming/outputfile""w");
if (!
$file) {
    echo 
"<p>Unable to open remote file for writing.\n";
    exit;
}
/* Write the data here. */
fwrite ($file$_SERVER['HTTP_USER_AGENT'] . "\n");
fclose ($file);
?>

Note:

You might get the idea from the example above that you can use this technique to write to a remote log file. Unfortunately that would not work because the fopen() call will fail if the remote file already exists. To do distributed logging like that, you should take a look at syslog().



Connection handling> <PUT method support
[edit] Last updated: Fri, 22 Jul 2011
 
add a note add a note User Contributed Notes Using remote files
mail at 3v1n0 dot net 29-Apr-2008 01:18
I've changed the function below to support the 4xx errors and the 30x redirects... This is a partial implementation yet but it's sufficient for the normal usage.

I've made a recursive implementation (if a 30x redirect is found), but it could be easily reverted to an iterative way (simple put something like while (!empty $url) at the beginning, and set the $url to an empty string if no 3xx/4xx status are found).

<?
function http_get($url, $range = 0)
{
   
$url_stuff = parse_url($url);
   
$port = isset($url_stuff['port']) ? $url_stuff['port'] : 80;
   
   
$fp = @fsockopen($url_stuff['host'], $port);
   
    if (!
$fp)
        return
false;
   
   
$query  = 'GET '.$url_stuff['path'].'?'.$url_stuff['query']." HTTP/1.1\r\n";
   
$query .= 'Host: '.$url_stuff['host']."\r\n";
   
$query .= 'Connection: close'."\r\n";
   
$query .= 'Cache-Control: no'."\r\n";
   
$query .= 'Accept-Ranges: bytes'."\r\n";
    if (
$range != 0)
       
$query .= 'Range: bytes='.$range.'-'."\r\n"; // -500
    //$query .= 'Referer: http:/...'."\r\n";
    //$query .= 'User-Agent: myphp'."\r\n";
   
$query .= "\r\n";
   
   
fwrite($fp, $query);
   
   
$chunksize = 1*(1024*1024);
   
$headersfound = false;

    while (!
feof($fp) && !$headersfound) {
       
$buffer .= @fread($fp, 1);
        if (
preg_match('/HTTP\/[0-9]\.[0-9][ ]+([0-9]{3}).*\r\n/', $buffer, $matches)) {
           
$headers['HTTP'] = $matches[1];
           
$buffer = '';
        } else if (
preg_match('/([^:][A-Za-z_-]+):[ ]+(.*)\r\n/', $buffer, $matches)) {
           
$headers[$matches[1]] = $matches[2];
           
$buffer = '';
        } else if (
preg_match('/^\r\n/', $buffer)) {
           
$headersfound = true;
           
$buffer = '';
        }

        if (
strlen($buffer) >= $chunksize)
            return
false;
    }

    if (
preg_match('/4[0-9]{2}/', $headers['HTTP']))
        return
false;
    else if (
preg_match('/3[0-9]{2}/', $headers['HTTP']) && !empty($headers['Location'])) {
       
$url = $headers['Location'];
        return
http_get($url, $range);
    }

    while (!
feof($fp) && $headersfound) {
       
$buffer = @fread($fp, $chunksize);
        echo
$buffer;
       
ob_flush();
       
flush();
    }

   
$status = fclose($fp);

    return
$status;
}
?>
geoffrey at nevra dot net 06-May-2006 10:53
Really, you should not send headers terminated by \n - it's not per-rfc supported by a HTTP server.

Instead, send as \r\n which is what the protocol specifies, and that regular expression would be matched anywhere, so match for something like /^Content-Length: \d+$/i on each header-line (headers are terminated by the regular expression  /(\r\n|[\r\n])/ - so preg_split on that. Remeber to use the appropriate flags, I can't be arsed to look them up)
heck at fas dot harvard dot edu 14-Sep-2004 07:06
The previous post is part right, part wrong. It's part right because it's true that the php script will run on the remote server, if it's capable of interpreting php scripts. You can see this by creating this script on a remote machine:
<?php
echo system("hostname");
?>
Then include that in a php file on your local machine. When you view it in a browser, you'll see the hostname of the remote machine.

However, that does not mean there are no security worries here. Just try replacing the previous script with this one:
<?php
echo "<?php system(\"hostname\"); ?>";
?>
I'm guessing you can figure out what that's gonna do.

So yes, remote includes can be a major security problem.
geoffrey at nevra dot net 05-Aug-2003 12:25
ok, here is the story:

I was trying to download remote images, finding urls throught apache indexs with regexps and fopen()ing them to get the datas. It didn't work. I thought about binary considerations. Putting the 'b' in the second argument of fopen didn't help much, my browser still didn't want to display the images. I finally understood by watching the datas i was getting from the remote host: it was an html page ! hey, i didn't know apache sent html pages when requesting images, did you ?
the right way is then to send an http request via fsockopen. Here comes my second problem, using explode("\n\n", $buffer); to get rid of the headers. The right way is to get the value of the Content-Lenght field and use it in substr($buffer, -$Content-Lenght);

finally, here is my own function to download these files:

<?php
function http_get($url)
{

   
$url_stuff = parse_url($url);
   
$port = isset($url_stuff['port']) ? $url_stuff['port'] : 80;

   
$fp = fsockopen($url_stuff['host'], $port);

   
$query  = 'GET ' . $url_stuff['path'] . " HTTP/1.0\n";
   
$query .= 'Host: ' . $url_stuff['host'];
   
$query .= "\n\n";

   
fwrite($fp, $query);

    while (
$tmp = fread($fp, 1024))
    {
       
$buffer .= $tmp;
    }

   
preg_match('/Content-Length: ([0-9]+)/', $buffer, $parts);
    return
substr($buffer, - $parts[1]);
?>

}

ho, maybe you'll say i could have parsed the page to get rid of the html stuff, but i wanted to experience http a little ;)

 
show source | credits | sitemap | contact | advertising | mirror sites