fopen

(PHP 4, PHP 5, PHP 7)

fopen打开文件或者 URL

说明

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

fopen()filename 指定的名字资源绑定到一个流上。

参数

filename

如果 filename 是 "scheme://..." 的格式,则被当成一个 URL,PHP 将搜索协议处理器(也被称为封装协议)来处理此模式。如果该协议尚未注册封装协议,PHP 将发出一条消息来帮助检查脚本中潜在的问题并将 filename 当成一个普通的文件名继续执行下去。

如果 PHP 认为 filename 指定的是一个本地文件,将尝试在该文件上打开一个流。该文件必须是 PHP 可以访问的,因此需要确认文件访问权限允许该访问。如果激活了安全模式或者 open_basedir 则会应用进一步的限制。

如果 PHP 认为 filename 指定的是一个已注册的协议,而该协议被注册为一个网络 URL,PHP 将检查并确认 allow_url_fopen 已被激活。如果关闭了,PHP 将发出一个警告,而 fopen 的调用则失败。

Note:

所支持的协议列表见支持的协议和封装协议。某些协议(也被称为 wrappers)支持 context 和/或 php.ini 选项。参见相应的页面哪些选项可以被设定(例如 php.ini 中用于 http wrapper 的 user_agent 值)。

On the Windows platform, be careful to escape any backslashes used in the path to the file, or use forward slashes.

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

mode

mode 参数指定了所要求到该流的访问类型。可以是以下:

fopen()mode 的可能值列表
mode 说明
'r' 只读方式打开,将文件指针指向文件头。
'r+' 读写方式打开,将文件指针指向文件头。
'w' 写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
'w+' 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
'a' 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
'a+' 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
'x' 创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。这和给 底层的 open(2) 系统调用指定 O_EXCL|O_CREAT 标记是等价的。
'x+' 创建并以读写方式打开,其他的行为和 'x' 一样。
'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer is positioned on the beginning of the file. This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested).
'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'.

Note:

不同的操作系统家族具有不同的行结束习惯。当写入一个文本文件并想插入一个新行时,需要使用符合操作系统的行结束符号。基于 Unix 的系统使用 \n 作为行结束字符,基于 Windows 的系统使用 \r\n 作为行结束字符,基于 Macintosh 的系统使用 \r 作为行结束字符。

如果写入文件时使用了错误的行结束符号,则其它应用程序打开这些文件时可能会表现得很怪异。

Windows 下提供了一个文本转换标记('t')可以透明地将 \n 转换为 \r\n。与此对应还可以使用 'b' 来强制使用二进制模式,这样就不会转换数据。要使用这些标记,要么用 'b' 或者用 't' 作为 mode 参数的最后一个字符。

默认的转换模式依赖于 SAPI 和所使用的 PHP 版本,因此为了便于移植鼓励总是指定恰当的标记。如果是操作纯文本文件并在脚本中使用了 \n 作为行结束符,但还要期望这些文件可以被其它应用程序例如 Notepad 读取,则在 mode 中使用 't'。在所有其它情况下使用 'b'

在操作二进制文件时如果没有指定 'b' 标记,可能会碰到一些奇怪的问题,包括坏掉的图片文件以及关于 \r\n 字符的奇怪问题。

Note:

为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。

Note:

再一次,为移植性考虑,强烈建议你重写那些依赖于 't' 模式的代码使其使用正确的行结束符并改成 'b' 模式。

use_include_path

如果也需要在 include_path 中搜寻文件的话,可以将可选的第三个参数 use_include_path 设为 '1' 或 TRUE

context

Note: 在 PHP 5.0.0 中增加了对上下文(Context)的支持。有关上下文(Context)的说明参见 Streams

返回值

成功时返回文件指针资源,如果打开失败,本函数返回 FALSE

错误/异常

如果打开失败,会产生一个 E_WARNING 错误。可以通过 @ 来屏蔽错误。

更新日志

版本 说明
4.3.2 自 PHP 4.3.2 起,对所有区别二进制和文本模式的平台默认模式都被设为二进制模式。如果在升级后脚本碰到问题,尝试暂时使用 't' 标记,直到所有的脚本都照以下所说的改为更具移植性以后。
4.3.2 增加了选项 'x''x+'
5.2.6 增加了选项 'c''c+'

范例

Example #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");
?>

注释

Warning

使用 SSL 时,Microsoft IIS 会违反协议不发送close_notify标记就关闭连接。PHP 会在到达数据尾端时报告"SSL: Fatal Protocol Error"。 要解决此问题,error_reporting 应设定为降低级别至不包含警告。 PHP 4.3.7 及更高版本可以在使用 https:// 包装器打开流时检测出有问题的 IIS 服务器软件 并抑制警告。在使用 fsockopen() 创建 ssl:// 套接字时, 开发者需检测并抑制此警告。

Note: 当启用 安全模式时, PHP 会在执行脚本时检查被脚本操作的目录是否与被执行的脚本有相同的 UID(所有者)。

Note:

如果在用服务器模块版本的 PHP 时在打开和写入文件上遇到问题,记住要确保所使用的文件和目录是服务器进程所能够访问的。

Note:

This function may also succeed when filename is a directory. If you are unsure whether filename is a file or a directory, you may need to use the is_dir() function before calling fopen().

参见

User Contributed Notes

petepostma-deletethis at gmail dot com 13-Apr-2017 12:40
The verbal descriptions take a while to read through to get a feel for the expected results for fopen modes. This csv table can help break it down for quicker understanding to find which mode you are looking for:

Mode,Creates,Reads,Writes,Pointer Starts,Truncates File,Notes,Purpose
r,,y,,beginning,,fails if file doesn't exist,basic read existing file
r+,,y,y,beginning,,fails if file doesn't exist,basic r/w existing file
w,y,,y,beginning+end,y,,"create, erase, write file"
w+,y,y,y,beginning+end,y,,"create, erase, write file with read option"
a,y,,y,end,,,"write from end of file, create if needed"
a+,y,y,y,end,,,"write from end of file, create if needed, with read options"
x,y,,y,beginning,,fails if file exists,"like w, but prevents over-writing an existing file"
x+,y,y,y,beginning,,fails if file exists,"like w+, but prevents over writing an existing file"
c,y,,y,beginning,,,open/create a file for writing without deleting current content
c+,y,y,y,beginning,,,"open/create a file that is read, and then written back down"
marcovtwout 19-Apr-2016 06:41
If you are getting a "HTTP request failed!" without further details, the socket timeout could be expired. This default to 60 seconds. See stream_set_timeout().
lp dot soni at yahoo dot co dot in 11-Oct-2015 04:12
For the directory separators use the PHP constant DIRECTORY_SEPARATOR.
qrworld.net 11-Nov-2014 05:02
Here you have a function found on the website http://softontherocks.blogspot.com/2014/11/funcion-para-escribir-en-un-fichero-log.html with an example of how to make a log file.

The function is this:

function writeLog($data) {
 list($usec, $sec) = explode(' ', microtime());
 $datetime = strftime("%Y%m%d %H:%M:%S",time());
 $msg = "$datetime'". sprintf("%06s",intval($usec*1000000)).": $data";
 $save_path = 'foo.txt';
 $fp = @fopen($save_path, 'a'); // open or create the file for writing and append info
 fputs($fp, "$msg\n"); // write the data in the opened file
 fclose($fp); // close the file
}
Antoine 05-Sep-2014 12:55
On a Windows webserver, when using fopen with a file path stored in a variable, PHP will return an error if the variable isn't encoded in ASCII, which may be the case if the file file path is retrieved from a database.

Possible workaround :
<?
$encoding = mb_detect_encoding($filePath);
$filePath = mb_convert_encoding($filePath, "ASCII", $encoding);
$filePath = str_replace("?", "", $filePath);
$filePath = addslashes($filePath);

if(file_exists($filePath)) {
    echo "File Found.";
    $handle       = fopen($filePath, "r");
    $fileContents = fread($handle, filesize($filePath));
    fclose($handle);
    if(!empty($fileContents)) {
        echo "<pre>".$fileContents."</pre>";
    }
}
else {
    echo "File Not Found.";
}
?>
simon dot riget at gamil dot com 22-May-2013 03:50
Writing and reading on a serial port.

If you are unable or unwilling to install the serial device library for PHP, its still possible to communicate through a serial port or USB device.

There are two issues to note:
- you must use a system call to set the port control options
- you must use NON blocking stream mode for reading (not for writing unless you use flow control)

<?php
// Set timeout to 500 ms
$timeout=microtime(true)+0.5;

// Set device controle options (See man page for stty)
exec("/bin/stty -F /dev/ttyS0 19200 sane raw cs8 hupcl cread clocal -echo -onlcr ");
   
// Open serial port
$fp=fopen("/dev/ttyS0","c+");
if(!
$fp) die("Can't open device");

// Set blocking mode for writing
stream_set_blocking($fp,1);
fwrite($fp,"foo\n");

// Set non blocking mode for reading
stream_set_blocking($fp,0);
do{
 
// Try to read one character from the device
 
$c=fgetc($fp);
 
 
// Wait for data to arive
 
if($c === false){
     
usleep(50000);
      continue;
  } 
 
 
$line.=$c;
   
}while(
$c!="\n" && microtime(true)<$timeout);
 
echo
"Responce: $line"
?>
apathetic012 at gmail dot com 05-Sep-2012 12:19
a variable $http_response_header is available when doing the fopen(). Which contains an array of the response header.
chapman at worldtakeoverindustries dot com 10-Mar-2012 04:25
Note - using fopen in 'w' mode will NOT update the modification time (filemtime) of a file like you may expect. You may want to issue a touch() after writing and closing the file which update its modification time. This may become critical in a caching situation, if you intend to keep your hair.
kasper at webmasteren dot eu 11-Feb-2012 05:36
"Do not use the following reserved device names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1,
LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names
followed immediately by an extension; for example, NUL.txt is not recommended.
For more information, see Namespaces"
it is a windows limitation.
see:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
php at richardneill dot org 01-Aug-2011 06:39
fopen() will block if the file to be opened is a fifo. This is true whether it's opened in "r" or "w" mode.  (See man 7 fifo: this is the correct, default behaviour; although Linux supports non-blocking fopen() of a fifo, PHP doesn't).
The consequence of this is that you can't discover whether an initial fifo read/write would block because to do that you need stream_select(), which in turn requires that fopen() has happened!
splogamurugan at gmail dot com 09-Jun-2011 11:13
While opening a file with multibyte data (Ex: données multi-octets), faced some issues with the encoding. Got to know that it uses  windows-1250. Used iconv to convert it to UTF-8 and it resolved the issue. 

<?php
function utf8_fopen_read($fileName) {
   
$fc = iconv('windows-1250', 'utf-8', file_get_contents($fileName));
   
$handle=fopen("php://memory", "rw");
   
fwrite($handle, $fc);
   
fseek($handle, 0);
    return
$handle;
}
?>

Example usage:

<?php
$fh
= utf8_fopen_read("./tpKpiBundle.csv");
while ((
$data = fgetcsv($fh, 1000, ",")) !== false) {
    foreach (
$data as $value) {
        echo
$value . "<br />\n";
    }
}
?>

Hope it helps.
owltech at larkandowl dot net 07-Feb-2011 08:20
[fopen note]

I have been trying unsuccessfully to upload and read a Mac OS file on a Linux server. Lots of records show up a just one big using only the following:

<?php $fhandle = fopen($file, 'r'); ?>
  or
<?php $fhandle = fopen($file, 'rb'); ?>

It does work, however, this way:

<?php
ini_set
('auto_detect_line_endings', TRUE);
$fhandle = fopen($file, 'r');
?>
Brad G 16-Oct-2010 11:10
While adding CFLAGS="-D_FILE_OFFSET_BITS=64" immediately before calling "./configure" on the PHP source will enable support for using fopen() on large files (greater than 2 GB), note that -- if such an installation of PHP is used in conjunction with Apache HTTPD [2.x], Apache will become completely unresponsive even when not serving output from a PHP application.

In order to gain large file support for non-web applications while maintaining the operability of Apache, consider making two distinct PHP installations:  one with the above CFLAGS specified during configuration (for non-web uses), and the other without this flag (for use with Apache).
eyrie88 at gmail dot com 01-Aug-2010 04:39
Be aware that fopen($url) also respects HTTP status headers. If the URL responds with a 1xx, 4xx, or 5xx status code, you will get a "failed to open stream: HTTP request failed!", followed by the HTTP status response. Same goes for file_get_contents($url)...
anfragen at tsgames dot de 27-May-2010 02:54
Since the http-wrapper doesn't support stat() and so you can't use file_exists() for url's, you can simply use a function like this:

<?php
function http_file_exists($url)
{
$f=@fopen($url,"r");
if(
$f)
{
fclose($f);
return
true;
}
return
false;
}
?>
Pastix 20-Jan-2010 12:04
If fopen() has been disabled for security reasons, is possible a porting FROM:

<?php
$f
=fopen($file,'rb');
$data='';
while(!
feof($f))
   
$data.=fread($f,$size);
fclose($f);
?>

TO:

<?php
$data
= file_get_contents($file); // (PHP 4 >= 4.3.0, PHP 5)
?>

and also a porting FROM:

<?php
$f
= fopen($file,'wb');
fwrite($f,$content,strlen($content));
fclose($f);
?>

TO:

<?php
$f
=file_put_contents($file, $content); // (PHP 5)
?>

For detail read the php manual.
rene 04-Jan-2010 11:43
if fopen() throws a E_WARNING "failed to open stream: HTTP request failed!" at you when opening a valid URL that you know returns data, i advise you to do the following before calling fopen($url,'r'):

<?php
ini_set
('user_agent', $_SERVER['HTTP_USER_AGENT']);
?>

or anyways, set that 'user_agent' with ini_set() to something valid.

thanks, pollita|at|php.net @ http://bugs.php.net/bug.php?id=22937#c64196 , for the clue to this
php at delhelsa dot com 24-Jun-2008 09: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 example.com and you're trying to access it with user blossom and password buttercup, the url would be:

ftp://blossom:buttercup@example.com//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.
sean downey 09-Feb-2008 09: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 03: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.
simon dot allen at swerve dot co dot nz 10-Apr-2007 04:56
using fopen to upload a file through ftp cannot overwrite that file - use curl instead
ceo at l-i-e dot com 11-Apr-2006 05: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 04: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 01: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 04: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 02: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 08: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) 17-Aug-2005 10: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 04: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.
Thomas Candrian tc_ at gmx dot ch 12-Nov-2004 04: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.
Jem Tallon 14-Apr-2004 12: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;
}
?>
richard dot quadling at carval dot co dot uk 04-Feb-2004 02: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.
sergiopaternoster at tiscali dot it 27-Nov-2003 02: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 12:03
PHP will open a directory if a path with no file name is supplied. This just bit me. I was not checking the filename part of a concatenated string.

For example:

<?php
$fd
= fopen('/home/mydir/' . $somefile, 'r');
?>

Will open the directory if $somefile = ''

If you attempt to read using the file handle you will get the binary directory contents. I tried append mode and it errors out so does not seem to be dangerous.

This is with FreeBSD 4.5 and PHP 4.3.1. Behaves the same on 4.1.1 and PHP 4.1.2. I have not tested other version/os combinations.
dan at cleandns dot com 19-Nov-2003 08:15
<?php
#going to update last users counter script since
#aborting a write because a file is locked is not correct.

$counter_file = '/tmp/counter.txt';
clearstatcache();
ignore_user_abort(true);     ## prevent refresh from aborting file operations and hosing file
if (file_exists($counter_file)) {
  
$fh = fopen($counter_file, 'r+');
    while(
1) {
      if (
flock($fh, LOCK_EX)) {
        
#$buffer = chop(fgets($fh, 2));
        
$buffer = chop(fread($fh, filesize($counter_file)));
        
$buffer++;
        
rewind($fh);
        
fwrite($fh, $buffer);
        
fflush($fh);
        
ftruncate($fh, ftell($fh));    
        
flock($fh, LOCK_UN);
         break;
      }
   }
}
else {
  
$fh = fopen($counter_file, 'w+');
  
fwrite($fh, "1");
  
$buffer="1";
}
fclose($fh);

print
"Count is $buffer";

?>
unshift at yahoo dot com 02-Jul-2003 01:58
It seems that fopen() errors when you attempt opening a url starting with HTTP:// as opposed to http:// - it is case sensitive.  In 4.3.1 anyway..."HTTP://", by not matching "http://" will tell the wrapper to look locally.  From the looks of the source, the same goes for HTTPS vs https, etc.
RobNar 17-Jun-2003 05:15
This is an addendum to ibetyouare at home dot com's note about Apache directory permissions.  If you are on a shared host and cannot tweak Apache's permissions directives then you might try setting the same thing in a .htaccess file.  Failing that, if you are having trouble just creating files then  set the directory permissions to allow writing (for whatever directory the file is supposed to be in) and include the following before fopen():

`touch /path/to/myfile/myfile.txt`;

That will usually create a new empty file that you can write to even when fopen fails. - PHP 4.3.0
Jhilton a at t nurv dot us 05-Jun-2003 09:54
Quick tip. If using fopen to make http requests that contain a querystring, it is advised that you urlencode() your values, else characters like @ can make fopen (or whatever wrapper it is using) throw an error.
04-Mar-2003 05:49
To overwrite a file with a new content without deleting it, and without changing the owner or access rights, it's best to not use:

<?php
$file
= fopen($filename, 'r+b'); // binary update mode
//...
ftruncate($file, 0);
fwrite($file, $my_stuff);
//...
fclose($file);
?>

but instead the faster one:

<?php
$file
= fopen($filename, 'r+b); // binary update mode
//...
rewind($file);
fwrite($file, $my_stuff);
fflush($file);
ftruncate($file, ftell($file));
//...
fclose($file);
?>

The reason is that truncating a file at size 0 forces the OS to deallocate all storage clusters used by the file, before you write your content which will be reallocated on disk.

The second code simply overwrites the existing content where it is already located on disk, and truncates any remaining bytes that may exist (if the new content is shorter than the old content). The "r+b" mode allows access for both read and write: the file can be kept opened after reading it and before rewriting the modified content.

It'
s particularly useful for files that are accessed often or have a size larger than a few kilobytes, as it saves lots of system I/O, and also limits the filesystem fragmentation if the updated file is quite large.

And
this method also works if the file is locked exclusively once opened (but I would rather recommend using another empty file for locking purpose, opened with "a+" access mode, in "/var/lock/yourapp/*" or other fast filesystems where filelocks are easily monitored and where the webserver running PHP is allowed to create and update lock files, and not forgetting to close the lock file after closing the content file).
01-Jul-2002 06:57
Note that if specifying the optional 'b' (binary) mode, it appears that it cannot be the first letter for some unaccountable reason. In other words, "br" doesn't work, while "rb" is ok!
php at themastermind1 dot com 24-Oct-2001 07:37
I have found that I can do fopen("COM1:", "r+"); to open the comport in windows. You have to make sure the comport isn't already open or you will get a permission denied.

I am still playing around with this but you have to somehow flush what you send to the comport if you are trying to communicate realtime with a device.
keithm at aoeex dot NOSPAM dot com 31-Jul-2001 02:19
I was working on a consol script for win32 and noticed a few things about it.  On win32 it appears that you can't re-open the input stream for reading, but rather you have to open it once, and read from there on.  Also, i don't know if this is a bug or what but it appears that fgets() reads until the new line anyway.  The number of characters returned is ok, but it will not halt reading and return to the script.  I don't know of a work around for this right now, but i'll keep working on it.

This is some code to work around the close and re-open of stdin.

<?php
function read($length='255'){
    if (!isset(
$GLOBALS['StdinPointer'])){
       
$GLOBALS['StdinPointer']=fopen("php://stdin","r");
    }
   
$line=fgets($GLOBALS['StdinPointer'],$length);
    return
trim($line);
}
echo
"Enter your name: ";
$name=read();
echo
"Enter your age: ";
$age=read();
echo
"Hi $name, Isn't it Great to be $age years old?";
@
fclose($StdinPointer);
?>
icon at mricon dot com 09-Nov-1999 11:44
If you're running PHP as apache module, it will always write files as "nobody", "www", "httpd", (or whatever user your webserver runs as) unless you specify a different user/group in httpd.conf, or compile apache with suexec support.
However, if you run PHP as a CGI wrapper, you may setuid the PHP executable to whatever user you wish (*severe* security issues apply). If you really want to be able to su to other user, I recommend compiling with suexec support.
AFAIK, PHP can't NOT use SuEXEC if apache does. If PHP is configured as an apache module it will act as whatever user the apache is. If apache SuEXEC's to otheruser:othergroup (e.g. root:root), that's what PHP will write files as, because it acts as a part of apache code. I suggest you double-check your SuEXEC configuration and settings. Note: you can't su to another user within the PHP code -- it has to be an apache directive, either through <VirtualHost>, or through .htaccess. Also note: I'm not sure how it all works (if it works at all) on Win32 platforms.
Check www.apache.org to see how it's done.