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

search for in the

fpassthru> <fnmatch
Last updated: Tue, 30 Jun 2009

view this page in

fopen

(PHP 4, PHP 5)

fopenファイルまたは URL をオープンする

説明

resource fopen ( string $filename , string $mode [, bool $use_include_path= false [, resource $context ]] )

fopen() は、filename で指定されたリソースをストリームに結び付けます。

パラメータ

filename

filename が "スキーム://..." の形式である場合、 それは URL とみなされ、PHP はそのプロトコルのハンドラ (ラッパーともいいます) を探します。 もしもそのプロトコルに対するラッパが登録されていない場合、 PHP はスクリプトに潜在的な問題があることを示す NOTICE を発行したうえで、 filename を通常のファイルとみなしてオープンすることを試みます。

PHP は、filename がローカルのファイルを示しているとみなすと、 そのファイルへのストリームをオープンします。 そのファイルはPHPからアクセスできるものでなければなりません。 ファイルのパーミッションが (パラメータで指定された) アクセスを許可されているかどうか確認する必要があります。 セーフモード または open_basedir を有効にしている場合は更なるアクセス制限が加えられることがあります。

filename が登録されているプロトコルを示していると PHP が判断し、かつそのプロトコルがネットワーク URL として登録されていれば、 PHP は allow_url_fopen が有効となっているかどうかチェックします。 もしこれがオフになっていると、PHP は warning を発行し fopen は失敗します。

注意: サポートされているプロトコルのリストは サポートされるプロトコル/ラッパー にあります。 いくつかのプロトコル (wrappersにも関連する) は context かつ/または php.ini のオプションをサポートします。 使用するプロトコルについてセットされるオプションのリストについては、 それぞれのページを見てください (例えば、 php.ini 上の user_agent の値は http ラッパーが使用します)。

Windows 環境では、ファイルパスで用いる全てのバックスラッシュを エスケープするかフォワードスラッシュを使用することに注意してください。

<?php
$handle 
fopen("c:\\data\\info.txt""r");
?>

mode

パラメータ mode は、 そのストリームに要するアクセス形式を指定します。 この指定は、下表のうちのどれかとなります。

fopen() で使用可能な mode のリスト
mode 説明
'r' 読み込みのみでオープンします。ファイルポインタをファイルの先頭に置きます。
'r+' 読み込み/書き出し用にオープンします。 ファイルポインタをファイルの先頭に置きます。
'w' 書き出しのみでオープンします。ファイルポインタをファイルの先頭に置き、 ファイルサイズをゼロにします。ファイルが存在しない場合には、 作成を試みます。
'w+' 読み込み/書き出し用でオープンします。 ファイルポインタをファイルの先頭に置き、 ファイルサイズをゼロにします。 ファイルが存在しない場合には、作成を試みます。
'a' 書き出し用のみでオープンします。ファイルポインタをファイルの終端に置きます。 ファイルが存在しない場合には、作成を試みます。
'a+' 読み込み/書き出し用でオープンします。 ファイルポインタをファイルの終端に置きます。 ファイルが存在しない場合には、作成を試みます。
'x' 書き込みのみでオープンします。ファイルポインタをファイルの先頭に置きます。 ファイルが既に存在する場合には fopen() は失敗し、 E_WARNING レベルのエラーを発行します。 ファイルが存在しない場合には新規作成を試みます。 これは open(2) システムコールにおける O_EXCL|O_CREAT フラグの指定と等価です。 このオプションはPHP4.3.2以降でサポートされ、また、 ローカルファイルに対してのみ有効です。
'x+' 読み込み/書き出し用でオープンします。ファイルポインタをファイルの先頭に置きます。 ファイルが既に存在する場合には fopen() は失敗し、 E_WARNING レベルのエラーを発行します。 これは open(2) システムコールにおける O_EXCL|O_CREAT フラグの指定と等価です。 このオプションは PHP 4.3.2 以降でサポートされ、また、 ローカルファイルに対してのみ有効です。

注意: オペレーティングシステムファミリが異なると行末も異なります。 テキストファイルに書き出し、そこに改行を加えたいとき、 オペレーティングシステムにあわせた正しい改行コードを使用する必要があります。 Unix ベースのシステムでは改行に \n キャラクタを使用します。 Windows ベースのシステムでは \r\n を使用します。 マッキントッシュベースのシステムでは \r を使用します。
間違った改行コードでファイルに書き込むと、 他のアプリケーション上でそのファイルを開いた際に変な風に見えてしまいます。
Windows上では、\n\r\nに透過的に変換する text-mode変換フラグ('t')が提供されます。 それに対し、'b'を使って強制的にバイナリモードにすることもできます。 その場合データの変換はされません。 このフラグを使用するには、'b' または 't'mode 引数の最後に追加してください。
デフォルトの変換モードは SAPI と使用している PHP のバージョンによって異なります。 したがって、互換性の意味から、常に適切なフラグを指定することが推奨されます。 plain-text ファイルを使用する場合には 't' モードを指定すべきであり、 改行に \n を使用すると、 メモ帳のようなアプリケーションで読めることを期待できます。 それ以外のケースでは 'b' を使うべきです。
バイナリファイルを扱っている際に 'b' フラグを指定しなかった場合、 画像ファイルが壊れたり、\r\n キャラクタがおかしくなる等の問題を抱えてしまうでしょう。

注意: 互換性維持のために、fopen() でファイルをオープンする際は 常に 'b' フラグを指定することが強く推奨されます。

注意: 互換性維持のために、't' モードを使用または依存しているコードを書き直し、 正しい改行コードと 'b' モードを代わりに使用することが、 強く推奨されます。

use_include_path

オプションの3番目の引数use_include_path に'1'又は TRUE を設定することにより、include_path のファイルの検索も行うこともできます。

context

注意: コンテキストのサポートは、 PHP 5.0.0 で追加されました。contexts の説明に関しては、 ストリーム 関数 を参照してください。

返り値

成功した場合にファイルポインタリソース、エラー時に FALSE を返します。

エラー / 例外

オープンが失敗するとこの関数は FALSE を返し、 E_WARNING レベルのエラーを発行します。 @ を使ってこの warning を抑制することもできます。

変更履歴

バージョン 説明
4.3.2 PHP 4.3.2 以降では、バイナリモードとテキストモードを区別する全ての プラットフォームにおいて、デフォルトのモードはバイナリにセットされます。 アップグレード後にスクリプトに問題が起きた場合は、 以上に述べたスクリプトの互換性を確保するまでの次善策として、 't' フラグを試してみてください。
4.3.2 'x' および 'x+' が追加されました。

例1 fopen() の例

<?php
$handle 
fopen("/home/rasmus/file.txt""r");
$handle fopen("/home/rasmus/file.gif""wb");
$handle fopen("http://www.example.com/""r");
$handle fopen("ftp://user:password@example.com/somefile.txt""w");
?>

注意

警告

IIS のような、いくつかの標準に 対応してない Web サーバは、PHP に警告を発生させるような手順でデータを送信します。 このようなサーバを使用する場合は、 error_reporting を警告を発生しないレベルまで小さくする必要があります。 PHP 4.3.7 以降では、https:// ラッパーでストリームをオープンする際に バグがある IIS サーバソフトウエアを検出することができ、この警告を抑制することができます。 あなたが ssl:// ソケットを作成するために fsockopen() を使用している場合、 自らこの警告を検出し、抑制する必要があります。

注意: セーフモード が有効の場合、PHP は、 操作を行うディレクトリが、実行するスクリプトと同じ UID (所有者)を有しているか どうかを確認します。

ファイルの読みこみ・書きこみ時に問題が発生し、 サーバーモジュール版のPHPを使用している場合、 使用するファイル・ディレクトリがサーバプロセスからアクセス可能かどうかを確認してください。

参考

  • サポートされるプロトコル/ラッパー
  • fclose() - オープンされたファイルポインタをクローズする
  • fgets() - ファイルポインタから 1 行取得する
  • fread() - バイナリセーフなファイルの読み込み
  • fwrite() - バイナリセーフなファイル書き込み処理
  • fsockopen() - インターネット接続もしくはUnix ドメインソケット接続をオープンする
  • file() - ファイル全体を読み込んで配列に格納する
  • file_exists() - ファイルまたはディレクトリが存在するかどうか調べる
  • is_readable() - ファイルが読み込み可能かどうかを知る
  • stream_set_timeout() - ストリームにタイムアウトを設定する
  • popen() - プロセスへのファイルポインタをオープンする
  • stream_context_create() - ストリームコンテキストを作成する



fpassthru> <fnmatch
Last updated: Tue, 30 Jun 2009
 
add a note add a note User Contributed Notes
fopen
gmdebby at gmail dot com
08-Jun-2009 10:49
I was wondering why was added the "x" mode, it works only if the file do not exists, will create it and open it in read only, it's useless !!
But I found something I could do with that.

Here is a little mk_file function.

<?php
function mk_file($filename) {
    if(!
is_file($filename)) {
       
fclose(fopen($filename,"x")); //create the file and close it
       
return true;
    } else return
false; //file already exists
}
?>

You can improve it, add chmod support etc...
php at delhelsa dot com
25-Jun-2008 04:27
With php 5.2.5 on Apache 2.2.4, accessing files on an ftp server with fopen() or readfile() requires an extra forwardslash if an absolute path is needed.

i.e., if a file called bullbes.txt is stored under /var/school/ on ftp server townsville and you're trying to access it with user blossom and password buttercup, the url would be:

ftp://blossom:buttercup@townsville//var/school/bubbles.txt

Note the two forwardslashes. It looks like the second one is needed so the server won't interpret the path as relative to blossom's home on townsville.
erk_3 at hotmail dot com
13-May-2008 12:48
If you are getting permission denied trying to write/read to a network resource, you have to change the system account that the apache service is runnning on.
However if you are on a domain, you will need to use the user name as:
user@domain.com

If you user the format: domain\username  the service will successfully start, but you will still receive errors trying to access the network resource.
webmaster at myeshop dot fr
26-Apr-2008 11:40
Also a small function useful for backup for example. It's a mixed between the fopen() and the mkdir() functions.

This function opens a file but also make the path recursively where the file is contained. This is helpful for ending to finish with "No such file or directory in" errors

<?php
function fopen_recursive($path, $mode, $chmod=0755){
 
preg_match('`^(.+)/([a-zA-Z0-9]+\.[a-z]+)$`i', $path, $matches);
 
$directory = $matches[1];
 
$file = $matches[2];

  if (!
is_dir($directory)){
    if (!
mkdir($directory, $chmod, 1)){
    return
FALSE;
    }
  }
 return
fopen ($path, $mode);
}
?>
jphansen at uga dot edu
23-Feb-2008 12:04
If you open a file with r+ and execute an fwrite(), writing less to the file than what it originally was, it will result in the difference being padded with the end of the file from the previous end of the file. Example:

<?php
// Open file for read and string modification
$file = "/test";
$fh = fopen($file, 'r+');
$contents = fread($fh, filesize($file));
$new_contents = str_replace("hello world", "hello", $contents);
fclose($fh);

// Open file to write
$fh = fopen($file, 'r+');
fwrite($fh, $new_contents);
fclose($fh);
?>

If the end of the file was "abcdefghij", you will notice that the difference in "hello world" and "hello", 6 characters, will be appended to the file, resulting in the new ending: "efghij". To obviate this, fopen() with +w instead, which truncates the file to zero length.
sean downey
09-Feb-2008 05:23
when using ssl / https on windows i would get the error:
"Warning: fopen(https://example.com): failed to open stream: Invalid argument in someSpecialFile.php on line 4344534"

This was because I did not have the extension "php_openssl.dll" enabled.

So if you have the same problem, goto your php.ini file and enable it :)
info at NOSPAMPLEASE dot c-eagle dot com
09-Oct-2007 10:14
If there is a file that´s excessively being rewritten by many different users, you´ll note that two almost-simultaneously accesses on that file could interfere with each other. For example if there´s a chat history containing only the last 25 chat lines. Now adding a line also means deleting the very first one. So while that whole writing is happening, another user might also add a line, reading the file, which, at this point, is incomplete, because it´s just being rewritten. The second user would then rewrite an incomplete file and add its line to it, meaning: you just got yourself some data loss!

If flock() was working at all, that might be the key to not let those interferences happen - but flock() mostly won´t work as expected (at least that´s my experience on any linux webserver I´ve tried), and writing own file-locking-functions comes with a lot of possible issues that would finally result in corrupted files. Even though it´s very unlikely, it´s not impossible and has happened to me already.

So I came up with another solution for the file-interference-problem:

1. A file that´s to be accessed will first be copied to a temp-file directory and its last filemtime() is being stored in a PHP-variable. The temp-file gets a random filename, ensuring no other process is able to interfere with this particular temp-file.
2. When the temp-file has been changed/rewritten/whatever, there´ll be a check whether the filemtime() of the original file has been changed since we copied it into our temp-directory.
2.1. If filemtime() is still the same, the temp-file will just be renamed/moved to the original filename, ensuring the original file is never in a temporary state - only the complete previous state or the complete new state.
2.2. But if filemtime() has been changed while our PHP-process wanted to change its file, the temp-file will just be deleted and our new PHP-fileclose-function will return a FALSE, enabling whatever called that function to do it again (ie. upto 5 times, until it returns TRUE).

These are the functions I´ve written for that purpose:

<?php
$dir_fileopen
= "../AN/INTERNAL/DIRECTORY/fileopen";

function
randomid() {
    return
time().substr(md5(microtime()), 0, rand(5, 12));
}

function
cfopen($filename, $mode, $overwriteanyway = false) {
    global
$dir_fileopen;
   
clearstatcache();
    do {
       
$id = md5(randomid(rand(), TRUE));
       
$tempfilename = $dir_fileopen."/".$id.md5($filename);
    } while(
file_exists($tempfilename));
    if (
file_exists($filename)) {
       
$newfile = false;
       
copy($filename, $tempfilename);
    }else{
       
$newfile = true;
    }
   
$fp = fopen($tempfilename, $mode);
    return
$fp ? array($fp, $filename, $id, @filemtime($filename), $newfile, $overwriteanyway) : false;
}

function
cfwrite($fp,$string) { return fwrite($fp[0], $string); }

function
cfclose($fp, $debug = "off") {
    global
$dir_fileopen;
   
$success = fclose($fp[0]);
   
clearstatcache();
   
$tempfilename = $dir_fileopen."/".$fp[2].md5($fp[1]);
    if ((@
filemtime($fp[1]) == $fp[3]) or ($fp[4]==true and !file_exists($fp[1])) or $fp[5]==true) {
       
rename($tempfilename, $fp[1]);
    }else{
       
unlink($tempfilename);
        if (
$debug != "off") echo "While writing, another process accessed $fp[1]. To ensure file-integrity, your changes were rejected.";
       
$success = false;
    }
    return
$success;
}
?>

$overwriteanyway, one of the parameters for cfopen(), means: If cfclose() is used and the original file has changed, this script won´t care and still overwrite the original file with the new temp file. Anyway there won´t be any writing-interference between two PHP processes, assuming there can be no absolute simultaneousness between two (or more) processes.
misc at n4te dot com
06-Oct-2007 10:21
The UTF-8 BOM is optional. PHP does not ignore it if it is present when reading UTF-8 encoded data. Here is a function that skips the BOM, if it exists.

<?php
// Reads past the UTF-8 bom if it is there.
function fopen_utf8 ($filename, $mode) {
   
$file = @fopen($filename, $mode);
   
$bom = fread($file, 3);
    if (
$bom != b"\xEF\xBB\xBF")
       
rewind($file, 0);
    else
        echo
"bom found!\n";
    return
$file;
}
?>
simon dot allen at swerve dot co dot nz
10-Apr-2007 11:56
using fopen to upload a file through ftp cannot overwrite that file - use curl instead
naidim at gmail dot com
29-Mar-2007 07:54
While PHP does not have a function to insert text into the middle of a file, it is not that complicated to do.

<?php
function addRSSItem($rssFile, $firstItem, $item){
   
// Backup file
   
if(!copy($rssFile, 'backup.rss')) die('Backup failed!');
   
// Store file contents in array
   
$arrFile = file($rssFile);
   
// Open file for output
   
if(($fh = fopen($rssFile,'w')) === FALSE){
        die(
'Failed to open file for writing!');
    }
   
// Set counters
   
$currentLine = 0;
   
$cntFile = count($arrFile);
   
// Write contents, inserting $item as first item
   
while( $currentLine <= $cntFile ){
        if(
$currentLine == $firstItem) fwrite($fh, $item);
       
fwrite($fh, $arrFile[$currentLine]);
       
$currentLine++;
    }
   
// Delete backup
   
unlink('backup.rss');
}

$data = "    <item>\n<title>$_POST['title]</title>\n".
 
"        <description>$_POST['description']</description>\n".
 
"        <pubDate>$_POST['date']</pubDate>\n".
 
"        <link>http://www.site.com/mp3s/".
 
basename($_FILES['fullPath']['name'])."</link>".
 
"        <enclosure url=\"http://www.site.com/mp3s/".
 
basename($_FILES['fullPath']['name']).
 
"\" length=\"$_FILES[fullPath][size]\" type=\"audio/mpeg\" />".
 
"    </item>\n";
addRSSItem('/var/www/html/rss/podcast.rss',20,$data);
?>
andrew at NOSPAM dot neonsurge dot com
10-Feb-2007 11:22
My recent findings on high-performance fopen/fsockopen usage.

Note #1: The performance comparison below regarding curl is obsolete when utilizing certain things in this comment.  My performance tests download and upload about 97% as fast as curl with a custom non-socket blocking HTTP Transport class written for a high performance system in PHP5.

Note #2: fopen and fsockopen have a "feature' that always forces DNS resolution.  Check this code...

<?php for ($i = 0; $i < 50; $i++) {
   
$errno = $errstr = "";
   
//$ip = gethostbyname("php.net");  $a = fsockopen($ip,22,$errno,$errstr,10);  //FAST way
   
$a = fsockopen("php.net",22,$errno,$errstr,10); //SLOW way
   
$ab = fread($a,4096); unset($a, $ab);
}
?>

fsockopen() and fopen() always force php.net to be resolved every time and in this example above it resolves the name 50 seperate times and does not use the local cache.  To get around this, gethostbyname() does use your local DNS cache properly, it will not try to get the IP from your DNS server 50 times.  The above code for me to a personal server took 87 seconds the fast way, and 5.74 seconds the slow way, a 650% increase.  And this is single-threaded!  ;)

Note #3: I see a lot of notes and people mentioning non-blocking sockets, especially for HTTP transport.  I thought I would share a little from my experience.  First, the above command fsockopen() allows you to specify a timeout, after you check if it's  opened properly (as you should _always_) you just need to...

<?php stream_set_blocking($a,0);?>

From this point on certain considerations must be taken.  Remember you are not blocking anymore, so when you want to write or read a lot of data it will always return to you instantly.  Which is important since you need to check the return value of your writes and reads against how much you expect to read/write.  For reading if you do not know how long it is, checking for EOF works also.

This is in fact a neat feature and state, since you can now make a read/write loop to send/receive a lot of data and check the time/timeout value(s) constantly.  If that timeout is hit you can throw back errors properly to whatever function/method/code called your transport function/class.  The graceful failure with custom shorter failure times allows your application to continue, especially web-based applications where fopen alone and even curl under certain circumstances does not follow your requested timeouts, it will wait a full 60-90 seconds, depending on your OS.

Good ways to test a custom non-blocking timeout supported transport method described above is to make one first, and then transfer a large file with it, and halfway through unplug your network cable.  Curl or fopen/fread/fwrite alone will croak and make your applications wait a full 60-90 seconds, whereas a nice custom class will check if no data has been transferred for 15 seconds (or less!) and will fail gracefully with a error.

If anyone is interested in chatting about this feel free to contact me or add to this comment.
perrog at gmail dot com
21-Jan-2007 09:05
Note: If you have opened the file in append mode ("a" or "a+"), any data you write to the file will always be appended, regardless of the file position. But PHP distinguish between read and write position, and you may freely read at any position, but when you write it will always append at the end.

If you don't want that write restriction, open the file in read-write mode ("r+") and then start by moving the file pointer to the end.

<?php
if (($fp = fopen($filename, "r+") === FALSE) {
 
// handle error
 
exit;
}

if (
fseek($fp, 0, SEEK_END) === -1) {
 
// handle error
 
exit;
}
?>
patryk dot szczyglowski at gmail dot com
20-Sep-2006 11:02
Watch out not to specify empty string as filename. It seems PHP is trying to get data from stdin which may end up in script timeout. It may not be trivial to find.

<?php
$fp
= fopen('', 'r'); // wrong
?>
ceo at l-i-e dot com
11-Apr-2006 12:13
If you need fopen() on a URL to timeout, you can do like:
<?php
  $timeout
= 3;
 
$old = ini_set('default_socket_timeout', $timeout);
 
$file = fopen('http://example.com', 'r');
 
ini_set('default_socket_timeout', $old);
 
stream_set_timeout($file, $timeout);
 
stream_set_blocking($file, 0);
 
//the rest is standard
?>
flobee
15-Jan-2006 12:58
download: i need a function to simulate a "wget url" and do not buffer the data in the memory to avoid thouse problems on large files:
<?php
function download($file_source, $file_target) {
       
$rh = fopen($file_source, 'rb');
       
$wh = fopen($file_target, 'wb');
        if (
$rh===false || $wh===false) {
// error reading or opening file
          
return true;
        }
        while (!
feof($rh)) {
            if (
fwrite($wh, fread($rh, 1024)) === FALSE) {
                  
// 'Download error: Cannot write to file ('.$file_target.')';
                  
return true;
               }
        }
       
fclose($rh);
       
fclose($wh);
       
// No error
       
return false;
    }
?>
info at b1g dot de
24-Oct-2005 08:54
Simple class to fetch a HTTP URL. Supports "Location:"-redirections. Useful for servers with allow_url_fopen=false. Works with SSL-secured hosts.

<?php
#usage:
$r = new HTTPRequest('http://www.example.com');
echo
$r->DownloadToString();

class
HTTPRequest
{
    var
$_fp;        // HTTP socket
   
var $_url;        // full URL
   
var $_host;        // HTTP host
   
var $_protocol;    // protocol (HTTP/HTTPS)
   
var $_uri;        // request URI
   
var $_port;        // port
   
    // scan url
   
function _scan_url()
    {
       
$req = $this->_url;
       
       
$pos = strpos($req, '://');
       
$this->_protocol = strtolower(substr($req, 0, $pos));
       
       
$req = substr($req, $pos+3);
       
$pos = strpos($req, '/');
        if(
$pos === false)
           
$pos = strlen($req);
       
$host = substr($req, 0, $pos);
       
        if(
strpos($host, ':') !== false)
        {
            list(
$this->_host, $this->_port) = explode(':', $host);
        }
        else
        {
           
$this->_host = $host;
           
$this->_port = ($this->_protocol == 'https') ? 443 : 80;
        }
       
       
$this->_uri = substr($req, $pos);
        if(
$this->_uri == '')
           
$this->_uri = '/';
    }
   
   
// constructor
   
function HTTPRequest($url)
    {
       
$this->_url = $url;
       
$this->_scan_url();
    }
   
   
// download URL to string
   
function DownloadToString()
    {
       
$crlf = "\r\n";
       
       
// generate request
       
$req = 'GET ' . $this->_uri . ' HTTP/1.0' . $crlf
           
.    'Host: ' . $this->_host . $crlf
           
.    $crlf;
       
       
// fetch
       
$this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '') . $this->_host, $this->_port);
       
fwrite($this->_fp, $req);
        while(
is_resource($this->_fp) && $this->_fp && !feof($this->_fp))
           
$response .= fread($this->_fp, 1024);
       
fclose($this->_fp);
       
       
// split header and body
       
$pos = strpos($response, $crlf . $crlf);
        if(
$pos === false)
            return(
$response);
       
$header = substr($response, 0, $pos);
       
$body = substr($response, $pos + 2 * strlen($crlf));
       
       
// parse headers
       
$headers = array();
       
$lines = explode($crlf, $header);
        foreach(
$lines as $line)
            if((
$pos = strpos($line, ':')) !== false)
               
$headers[strtolower(trim(substr($line, 0, $pos)))] = trim(substr($line, $pos+1));
       
       
// redirection?
       
if(isset($headers['location']))
        {
           
$http = new HTTPRequest($headers['location']);
            return(
$http->DownloadToString($http));
        }
        else
        {
            return(
$body);
        }
    }
}
?>
admin at sellchain dot com
17-Oct-2005 11:34
TIP: If you are using fopen and fread to read HTTP or FTP or Remote Files, and experiencing some performance issues such as stalling, slowing down and otherwise, then it's time you learned a thing called cURL.

Performance Comparison:

10 per minute for fopen/fread for 100 HTTP files
2000 per minute for cURL for 2000 HTTP files

cURL should be used for opening HTTP and FTP files, it is EXTREMELY reliable, even when it comes to performance.

I noticed when using too many scripts at the same time to download the data from the site I was harvesting from, fopen and fread would go into deadlock. When using cURL i can open 50 windows, running 10 URL's from each window, and getting the best performance possible.

Just a Tip :)
nefertari at nefertari dot be
20-Sep-2005 09:47
Important note:

You have always to use the real path name for a file with the command fopen [for example: fopen($filename, 'w')], never use a symbolic link, it will not work (unable to open $filename).
durwood at speakeasy dot NOSPAM dot net
07-Sep-2005 03:43
I couldn't for the life of me get a certain php script working when i moved my server to a new Fedora 4 installation. The problem was that fopen() was failing when trying to access a file as a URL through apache -- even though it worked fine when run from the shell and even though the file was readily readable from any browser.  After trying to place blame on Apache, RedHat, and even my cat and dog, I finally ran across this bug report on Redhat's website:

https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=164700

Basically the problem was SELinux (which I knew nothing about) -- you have to run the following command in order for SELinux to allow php to open a web file:

/usr/sbin/setsebool httpd_can_network_connect=1

To make the change permanent, run it with the -P option:

/usr/sbin/setsebool -P httpd_can_network_connect=1

Hope this helps others out -- it sure took me a long time to track down the problem.
Luiz Miguel Axcar (lmaxcar at yahoo dot com dot br)
18-Aug-2005 05:11
If you are getting message "Warning: fopen(): URL file-access is disabled in the server configuration", you can use function below to get the content from a local or remote file.

Function uses CURL lib, follow the link to get help: http://www.php.net/curl

<?php
/*
   * @return string
   * @param string $url
   * @desc Return string content from a remote file
   * @author Luiz Miguel Axcar (lmaxcar@yahoo.com.br)
*/

function get_content($url)
{
   
$ch = curl_init();

   
curl_setopt ($ch, CURLOPT_URL, $url);
   
curl_setopt ($ch, CURLOPT_HEADER, 0);

   
ob_start();

   
curl_exec ($ch);
   
curl_close ($ch);
   
$string = ob_get_contents();

   
ob_end_clean();
   
    return
$string;    
}

#usage:
$content = get_content ("http://www.php.net");
var_dump ($content);
?>
ideacode
03-Aug-2005 11:28
Note that whether you may open directories is operating system dependent. The following lines:

<?php
// Windows ($fh === false)
$fh = fopen('c:\\Temp', 'r');

// UNIX (is_resource($fh) === true)
$fh = fopen('/tmp', 'r');
?>

demonstrate that on Windows (2000, probably XP) you may not open a directory (the error is "Permission Denied"), regardless of the security permissions on that directory.

On UNIX, you may happily read the directory format for the native filesystem.
abesharp at yahoo dot co dot uk
05-Apr-2005 08:12
This function has a basic implementation of HTTP Digest Authentication (as per RFC 2617) to get a file from a web server which requires digest authentication (as opposed to basic authentication - the difference being that, with basic, your password is sent to the server as plain text, whereas with digest, it is hashed with a server-supplied nonce to protect against sniffing and replay attacks).

You just supply the host (e.g www.example.com), the name of the file you want (e.g protected_page.html), and the necessary username and password, and the function returns the contents of the protected file (or the error message that the server sends, if you supplied the wrong credentials).

If the server only supports a QOP of auth-int (rather then auth) this function won't work, but can be easily modified with reference to the RFC at http://www.ietf.org/rfc/rfc2617.txt

<?php
function readHTTPDigestAuthenticatedFile($host,$file,$username,$password)
{
    if (!
$fp=fsockopen($host,80, $errno, $errstr, 15))
        return
false;
       
   
//first do the non-authenticated header so that the server
    //sends back a 401 error containing its nonce and opaque
   
$out = "GET /$file HTTP/1.1\r\n";
      
$out .= "Host: $host\r\n";
      
$out .= "Connection: Close\r\n\r\n";

    
fwrite($fp, $out);

   
//read the reply and look for the WWW-Authenticate element
   
while (!feof($fp))
    {
       
$line=fgets($fp, 512);
       
        if (
strpos($line,"WWW-Authenticate:")!==false)
           
$authline=trim(substr($line,18));
    }
   
   
fclose($fp);
      
   
//split up the WWW-Authenticate string to find digest-realm,nonce and opaque values
    //if qop value is presented as a comma-seperated list (e.g auth,auth-int) then it won't be retrieved correctly
    //but that doesn't matter because going to use 'auth' anyway
   
$authlinearr=explode(",",$authline);
   
$autharr=array();
   
    foreach (
$authlinearr as $el)
    {
       
$elarr=explode("=",$el);
       
//the substr here is used to remove the double quotes from the values
       
$autharr[trim($elarr[0])]=substr($elarr[1],1,strlen($elarr[1])-2);
    }
   
    foreach (
$autharr as $k=>$v)
        echo(
"$k ==> $v\r\n");
   
   
//these are all the vals required from the server
   
$nonce=$autharr['nonce'];
   
$opaque=$autharr['opaque'];
   
$drealm=$autharr['Digest realm'];
   
   
//client nonce can be anything since this authentication session is not going to be persistent
    //likewise for the cookie - just call it MyCookie
   
$cnonce="sausages";
   
   
//calculate the hashes of A1 and A2 as described in RFC 2617
   
$a1="$username:$drealm:$password";$a2="GET:/$file";
   
$ha1=md5($a1);$ha2=md5($a2);
   
   
//calculate the response hash as described in RFC 2617
   
$concat = $ha1.':'.$nonce.':00000001:'.$cnonce.':auth:'.$ha2;
   
$response=md5($concat);
   
   
//put together the Authorization Request Header
   
$out = "GET /$file HTTP/1.1\r\n";
      
$out .= "Host: $host\r\n";
   
$out .= "Connection: Close\r\n";
   
$out .= "Cookie: cookie=MyCookie\r\n";
   
$out .= "Authorization: Digest username=\"$username\", realm=\"$drealm\", qop=\"auth\", algorithm=\"MD5\", uri=\"/$file\", nonce=\"$nonce\", nc=00000001, cnonce=\"$cnonce\", opaque=\"$opaque\", response=\"$response\"\r\n\r\n";
   
    if (!
$fp=fsockopen($host,80, $errno, $errstr, 15))
        return
false;
   
   
fwrite($fp, $out);
   
   
//read in a string which is the contents of the required file
   
while (!feof($fp))
    {
       
$str.=fgets($fp, 512);
    }
   
   
fclose($fp);
   
    return
$str;
}

?>
nuno at ideianet dot pt
04-Mar-2005 10:03
In IIS you must add the group Authenticated Users with write and modify permissions in the file where you want to write if you are in a Protected directory (Basic or Digest authentication) and want to write to a file in a Unprotected directory (Anonymous Access) in order to get permission to do that. Otherwise you will get the message: PHP Warning: fopen(x.txt): failed to open stream: Permission denied in c:\web\x\x.php on line 3 PHP Warning: fwrite(): supplied argument is not a valid stream resource in c:\web\x\x.php on line 10
Thomas Candrian tc_ at gmx dot ch
12-Nov-2004 12:35
With this it isn't possible to get data from another port than 80 (and 443) - at least for me. Because of that I've made this function who gets data from every port you want using HTTP:

<?php;
function
getcontent($server, $port, $file)
{
   
$cont = "";
   
$ip = gethostbyname($server);
   
$fp = fsockopen($ip, $port);
    if (!
$fp)
    {
        return
"Unknown";
    }
    else
    {
       
$com = "GET $file HTTP/1.1\r\nAccept: */*\r\nAccept-Language: de-ch\r\nAccept-Encoding: gzip, deflate\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\nHost: $server:$port\r\nConnection: Keep-Alive\r\n\r\n";
       
fputs($fp, $com);
        while (!
feof($fp))
        {
           
$cont .= fread($fp, 500);
        }
       
fclose($fp);
       
$cont = substr($cont, strpos($cont, "\r\n\r\n") + 4);
        return
$cont;
    }
}
echo
getcontent("www.myhost.com", "81", "/"));
?>

Works fine for me. Had to do this especially for a shoutcast server, which only delivered the HTML-file if the user-agent was given.
pflaume dot NOSPAM at NOSPAM dot gmx dot de
07-Nov-2004 07:31
fopen() and PROXY

I wondered why there is no possibility to use fopen() through a proxy in php. The solution posted above did not work for me.

This little function gets http through a given proxy:

<?php
function proxy_url($proxy_url)
{
   
$proxy_name = '127.0.0.1';
   
$proxy_port = 4001;
   
$proxy_cont = '';

   
$proxy_fp = fsockopen($proxy_name, $proxy_port);
    if (!
$proxy_fp)    {return false;}
   
fputs($proxy_fp, "GET $proxy_url HTTP/1.0\r\nHost: $proxy_name\r\n\r\n");
    while(!
feof($proxy_fp)) {$proxy_cont .= fread($proxy_fp,4096);}
   
fclose($proxy_fp);
   
$proxy_cont = substr($proxy_cont, strpos($proxy_cont,"\r\n\r\n")+4);
    return
$proxy_cont;
}
?>
justin at redwiredesign dot com
15-Jul-2004 04:03
One thing worth noting is that if you use the fopen command to open an HTTP stream, and the URL you're trying to access is invalid or generates an error response, (i.e. 404 Not found), the fopen call will return false.
Jem Tallon
14-Apr-2004 07:11
If you're using fopen to open a URL that requires authorization, you might need to force a HTTP/1.0 request for it since fopen won't support HTTP/1.1 requests. You can do that by setting your user_agent to one that is known only to support HTTP/1.0 (most webservers will be configured to force HTTP/1.0 for some browsers). Here's what worked for me:

<?php
$returned
=URLopen("http://$username:$password@example.com");

function
URLopen($url)
{
       
// Fake the browser type
       
ini_set('user_agent','MSIE 4\.0b2;');

       
$dh = fopen("$url",'r');
       
$result = fread($dh,8192);                                                                                                                            
        return
$result;
}
?>
php at gotdoof dot com
04-Apr-2004 01:19
Note that opening a fifo with fopen() will block the php process until data is sent to it. That means any function you have registered as a shutdown function (register_shutdown_function()) will not be called when the user disconnects, and the process will keep running in the background, waiting for input. I know of no way around this, besides using some other means of IPC.
richard dot quadling at carval dot co dot uk
04-Feb-2004 10:04
The issue involving some sites requiring a valid user-agent string when using fopen can easily be resolved by setting the user_agent string in the PHP.INI file.

If you do not have access to the PHP.INI file, then the use of

ini_set('user_agent','Mozilla: (compatible; Windows XP)');

should also work.

The actual agent string is up to you. If you want to identify to the sites that you are using PHP ...

ini_set('user_agent','PHP');

would do.

Regards,

Richard Quadling.
29-Jan-2004 04:34
If you are connecting to your ftp server through a router doing NAT (such as the Zyxel 128L prestige router/bridge we are using) by doing say an <?php fopen("ftp://ftpusername:ftppassword@example.com/".$file_name, "w") ?>, then this could fail. You will get php_hostconnect connection failed error. This is because fopen() function uses a passive ftp connection which the Zyxel router does not support, even though your ftp server may be configured to allow the passive connections which php fopen() function is using. Note that $file_name is the file we want to ftp to the remote server eg could be file.txt.

Thus an alternative would be to do create the file you want in a local directory of your machine or in the webserver where your php files reside eg use fwrite() as documented in the manual. Once you have the $file_name you want to ftp created, do the following:

<?php
ftp_connect
($ftp_server);
//which can connect to the ftp server using an active connection.
ftp_login ($conn_id, $ftp_username."@".$ftp_server, $ftp_password);
$fp = fopen($PATH."".$file_name, 'r');
// eg. $fp = fopen("http://www.yourwebsite.com/".$file_name, 'r');
//turn off passive mode transfers
ftp_pasv ($conn_id, false);
//now upload $file_name
ftp_fput($conn_id, $file_name, $fp, FTP_ASCII));
?>

Your file should now be in your ftp server, having used an active connection.
sergiopaternoster at tiscali dot it
27-Nov-2003 10:11
If you want to open large files (more than 2GB) that's what I did and it works: you should recompile your php with the CFLAGS="-D_FILE_OFFSET_BITS=64" ./configure etc... This tells to your compiler (I tested only gcc on PHP-4.3.4 binary on Linux and Solaris) to make the PHP parser binary large file aware. This way fopen() will not give you the "Value too large for defined data type" error message.
God bless PHP
ciao
Sergio Paternoster
ken dot gregg at rwre dot com
26-Nov-2003 08:03
PHP will open a directory if a path with no file name is supplied. This just bit me. I was not che