fopen

(PHP 4, PHP 5, PHP 7, PHP 8)

fopen打开文件或 URL

描述

fopen(
    字符串 $filename,
    字符串 $mode,
    布尔值 $use_include_path = false,
    ?资源 $context = null
): 资源|false

fopen() 将由 filename 指定的命名资源绑定到流。

参数

filename

如果 filename 采用 "scheme://..." 的形式,则假定它是一个 URL,PHP 将搜索该方案的协议处理程序(也称为包装器)。如果未注册该协议的包装器,PHP 将发出一个通知以帮助您跟踪脚本中潜在的问题,然后继续执行,就像 filename 指定一个普通文件一样。

如果 PHP 确定 filename 指定了一个本地文件,那么它将尝试在该文件上打开一个流。文件必须可供 PHP 访问,因此您需要确保文件访问权限允许此访问。如果您已启用 open_basedir,则可能会应用进一步的限制。

如果 PHP 确定 filename 指定了一个已注册的协议,并且该协议被注册为网络 URL,PHP 将检查以确保 allow_url_fopen 已启用。如果它被关闭,PHP 将发出警告,并且 fopen() 调用将失败。

注意:

支持的协议列表可以在 支持的协议和包装器 中找到。一些协议(也称为 包装器)支持 context 和/或 php.ini 选项。有关可以设置的选项列表,请参阅所用协议的特定页面。(例如,php.iniuser_agenthttp 包装器使用)。

在 Windows 平台上,请注意转义路径中使用的任何反斜杠,或使用正斜杠。

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

mode

mode 参数指定您对流所需的访问类型。它可以是以下任何一个

使用 modefopen() 的可能模式列表
mode 描述
'r' 仅打开以供读取;将文件指针置于文件开头。
'r+' 打开以供读写;将文件指针置于文件开头。
'w' 仅打开以供写入;将文件指针置于文件开头并截断文件为零长度。如果文件不存在,则尝试创建它。
'w+' 打开以供读写;否则其行为与 'w' 相同。
'a' 仅打开以供写入;将文件指针置于文件末尾。如果文件不存在,则尝试创建它。在此模式下,fseek() 不会产生任何效果,写入始终追加。
'a+' 打开以供读写;将文件指针置于文件末尾。如果文件不存在,则尝试创建它。在此模式下,fseek() 仅影响读取位置,写入始终追加。
'x' 创建并仅打开以供写入;将文件指针置于文件开头。如果文件已存在,则 fopen() 调用将失败,返回 false 并生成级别为 E_WARNING 的错误。如果文件不存在,则尝试创建它。这相当于为底层的 open(2) 系统调用指定 O_EXCL|O_CREAT 标志。
'x+' 创建并打开以供读写;否则其行为与 'x' 相同。
'c' 仅打开文件以供写入。如果文件不存在,则创建它。如果它存在,则不会被截断(与 'w' 相反),也不会导致对此函数的调用失败(与 'x' 的情况一样)。文件指针位于文件开头。这可能对在尝试修改文件之前获取建议锁(参见 flock())很有用,因为使用 'w' 可能会在获得锁之前截断文件(如果需要截断,可以在请求锁后使用 ftruncate())。
'c+' 打开文件以供读写;否则其行为与 'c' 相同。
'e' 在打开的文件描述符上设置关闭执行标志。仅在 POSIX.1-2008 兼容系统上编译的 PHP 中可用。

注意:

不同的操作系统系列具有不同的换行符约定。当您写入文本文件并想要插入换行符时,您需要使用操作系统正确的换行符字符。基于 Unix 的系统使用 \n 作为换行符字符,基于 Windows 的系统使用 \r\n 作为换行符字符,而基于 Macintosh 的系统(Mac OS Classic)使用 \r 作为换行符字符。

如果您在写入文件时使用错误的换行符字符,您可能会发现其他打开这些文件的应用程序会“看起来很奇怪”。

Windows 提供了一个文本模式转换标志 ('t'),它将在处理文件时透明地将 \n 转换为 \r\n。相反,您也可以使用 'b' 强制二进制模式,这将不会转换您的数据。要使用这些标志,请将 'b''t' 作为 mode 参数的最后一个字符指定。

默认转换模式为 'b'。如果您正在处理纯文本文件并且在脚本中使用 \n 来分隔换行符,但希望您的文件可以使用诸如旧版本的记事本等应用程序读取,则可以使用 't' 模式。在所有其他情况下,您应该使用 'b'

如果您在处理二进制文件时指定了 't' 标志,您可能会遇到数据方面奇怪的问题,包括损坏的图像文件和 \r\n 字符方面的奇怪问题。

注意:

为了可移植性,还强烈建议您重新编写使用或依赖 't' 模式的代码,以便它改为使用正确的换行符和 'b' 模式。

注意: modephp://outputphp://inputphp://stdinphp://stdoutphp://stderrphp://fd 流包装器忽略。

use_include_path

如果您希望在 include_path 中搜索文件,也可以将可选的第三个 use_include_path 参数设置为 true

context

一个 上下文流 资源

返回值

如果成功,则返回文件指针资源,如果失败,则返回 false

错误/异常

如果失败,将发出 E_WARNING

变更日志

版本 描述
7.0.16, 7.1.2 添加了 'e' 选项。

示例

示例 #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:[email protected]/somefile.txt", "w");
?>

注意

警告

在使用 SSL 时,Microsoft IIS 会违反协议,在没有发送 close_notify 指示器的情况下关闭连接。PHP 会在您到达数据末尾时将其报告为“SSL: Fatal Protocol Error”。为了解决这个问题,error_reporting 的值应该降低到不包含警告的级别。当您使用 https:// 协议打开流时,PHP 可以检测到有问题的 IIS 服务器软件,并将抑制警告。当使用 fsockopen() 创建 ssl:// 套接字时,开发者负责检测和抑制此警告。

注意:

如果您在读取和写入文件时遇到问题,并且您使用的是 PHP 的服务器模块版本,请务必确保您使用的文件和目录对服务器进程是可访问的。

注意:

filename 是一个目录时,此函数也可能成功。如果您不确定 filename 是一个文件还是一个目录,您可能需要在调用 fopen() 之前使用 is_dir() 函数。

参见

添加笔记

用户贡献的笔记 24 条笔记

chapman at worldtakeoverindustries dot com
12 年前
注意 - 在 'w' 模式下使用 fopen 不会像您预期的那样更新文件的修改时间 (filemtime)。您可能希望在写入并关闭文件后执行 touch(),以更新其修改时间。这在缓存情况下可能至关重要,如果您想保留您的头发。
匿名
3 年前
/***** 友好提醒 *****/
非常重要。除非您想删除文件中的所有内容,否则请不要使用 "w" 标志。
php-manual at merlindynamics dot com
4 年前
有一个未记录的模式可以使 fopen 非阻塞(在 Windows 上不起作用)。通过在模式参数中添加 'n',fopen 不会阻塞,但是如果管道不存在,则会引发错误。

$fp = fopen("/tmp/debug", "a"); // 如果管道不存在,则阻塞

$fp = fopen("/tmp/debug", "an"); // 如果管道不存在,则引发错误
php at delhelsa dot com
16 年前
在 Apache 2.2.4 上的 php 5.2.5 中,使用 fopen() 或 readfile() 访问 ftp 服务器上的文件需要额外的斜杠,如果需要绝对路径。

例如,如果名为 bullbes.txt 的文件存储在 ftp 服务器 example.com 的 /var/school/ 下,并且您尝试使用用户 blossom 和密码 buttercup 访问它,则 url 将是

ftp://blossom:[email protected]//var/school/bubbles.txt

请注意两个斜杠。看起来第二个斜杠是必需的,这样服务器就不会将路径解释为相对于 blossom 在 townsville 的主目录。
petepostma-deletethis at gmail dot com
7 年前
对 fopen 模式的文字描述需要一些时间才能读完,才能了解预期的结果。此 csv 表格可以帮助您更快地理解它,以找到您要查找的模式

模式,创建,读取,写入,指针开始,截断文件,笔记,目的
r,,y,,开始,,如果文件不存在则失败,基本读取现有文件
r+,,y,y,开始,,如果文件不存在则失败,基本读取/写入现有文件
w,y,,y,开始+结束,y,,"创建、擦除、写入文件"
w+,y,y,y,开始+结束,y,,"创建、擦除、写入文件,并具有读取选项"
a,y,,y,结束,,,"从文件末尾写入,如果需要则创建"
a+,y,y,y,结束,,,"从文件末尾写入,如果需要则创建,并具有读取选项"
x,y,,y,开始,,如果文件存在则失败,"类似于 w,但阻止覆盖现有文件"
x+,y,y,y,开始,,如果文件存在则失败,"类似于 w+,但阻止覆盖现有文件"
c,y,,y,开始,,,打开/创建文件以写入,而不删除当前内容
c+,y,y,y,开始,,,"打开/创建文件,读取后写入"
ideacode
19 年前
请注意,您是否可以打开目录取决于操作系统。以下几行

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

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

表明在 Windows(2000,可能是 XP)上,您可能无法打开目录(错误是“拒绝访问”),无论该目录的安全权限如何。

在 UNIX 上,您可以愉快地读取本机文件系统的目录格式。
durwood at speakeasy dot NOSPAM dot net
18 年前
当我将服务器迁移到新的 Fedora 4 安装时,我无法让某个 php 脚本正常运行。问题是 fopen() 在尝试通过 apache 访问文件作为 URL 时失败了 - 即使在从 shell 运行时它工作正常,即使该文件可以通过任何浏览器轻松读取。在试图将责任归咎于 Apache、RedHat,甚至我的猫和狗之后,我终于在 Redhat 的网站上看到了这个错误报告

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

基本上问题是 SELinux(我对此一无所知) - 您必须运行以下命令才能让 SELinux 允许 php 打开 web 文件

/usr/sbin/setsebool httpd_can_network_connect=1

要使更改永久生效,请使用 -P 选项运行它

/usr/sbin/setsebool -P httpd_can_network_connect=1

希望这能帮助其他人 - 我花了很长时间才找到这个问题。
etters dot ayoub at gmail dot com
6 年前
此函数在创建文件夹之前检查递归权限和父文件夹的递归存在。为了避免产生错误/警告。

/**
* 此函数检查递归权限和父文件夹的递归存在。
* 在创建文件夹之前。为了避免产生错误/警告。
*
* @return bool
* true 文件夹已创建或存在且可写。
* False 文件夹不存在且无法创建。
*/
function createWritableFolder($folder)
{
if (file_exists($folder)) {
// 文件夹存在。
return is_writable($folder);
}
// 文件夹不存在,检查父文件夹。
$folderParent = dirname($folder);
if($folderParent != '.' && $folderParent != '/' ) {
if(!createWritableFolder(dirname($folder))) {
// 无法创建父文件夹。
return false;
}
// 父文件夹已创建。
}

if ( is_writable($folderParent) ) {
// 父文件夹可写。
if ( mkdir($folder, 0777, true) ) {
// 文件夹已创建。
return true;
}
// 无法创建文件夹。
}
// 父文件夹不可写。
return false;
}

/**
* 此函数检查递归权限和父文件夹的递归存在。
* 在创建文件/文件夹之前。
*
* @return bool
* true 已创建或文件存在且可写。
* False 文件不存在且无法创建。
*/
function createWritableFile($file)
{
// 检查配置文件是否存在。
if (file_exists($file)) {
// 检查配置文件是否可写。
return is_writable($file);
}

// 检查配置文件是否存在,并尝试创建配置文件。
if(createWritableFolder(dirname($file)) && ($handle = fopen($file, 'a'))) {
fclose($handle);
return true; // 配置文件已创建。
}
// 无法访问配置文件。
return false;
}
php at richardneill dot org
13 年前
如果要打开的文件是 fifo,则 fopen() 会阻塞。这在以 "r" 或 "w" 模式打开时都是如此。(参见 man 7 fifo:这是正确的默认行为;虽然 Linux 支持 fifo 的非阻塞 fopen(),但 PHP 不支持)。
这会导致您无法发现初始 fifo 读取/写入是否会阻塞,因为要做到这一点,您需要 stream_select(),而 stream_select() 又需要 fopen() 已完成!
splogamurugan at gmail dot com
13 年前
在使用多字节数据(例如:données multi-octets)打开文件时,遇到了编码问题。得知它使用的是 windows-1250。使用 iconv 将其转换为 UTF-8,解决了问题。

<?php
函数 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);
返回
$handle;
}
?>

示例用法

<?php
$fh
= utf8_fopen_read("./tpKpiBundle.csv");
当 ((
$data = fgetcsv($fh, 1000, ",")) 不等于 false) {
遍历
$data 作为 $value {
回显
$value . "<br />\n";
}
}
?>

希望有帮助。
dan at cleandns dot com
20 年前
<?php
# 由于文件被锁而中止写入是不正确的,所以要更新最后一个用户计数脚本。
#
$counter_file = '/tmp/counter.txt';
clearstatcache();
ignore_user_abort(true); ## 阻止刷新中止文件操作并破坏文件。
如果 (file_exists($counter_file)) {
$fh = fopen($counter_file, 'r+');
当(
1) {
如果 (
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);
中断;
}
}
}
否则 {
$fh = fopen($counter_file, 'w+');
fwrite($fh, "1");
$buffer="1";
}
fclose($fh);

打印
"Count is $buffer";

?>
info at b1g dot de
18 年前
一个简单的类来获取 HTTP URL。支持“Location:"-重定向。对 allow_url_fopen=false 的服务器很有用。适用于使用 SSL 安全的服务器。

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

class
HTTPRequest
{
var
$_fp; // HTTP 套接字
var $_url; // 完整 URL
var $_host; // HTTP 主机
var $_protocol; // 协议 (HTTP/HTTPS)
var $_uri; // 请求 URI
var $_port; // 端口

// 扫描 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 = '/';
}

// 构造函数
function HTTPRequest($url)
{
$this->_url = $url;
$this->_scan_url();
}

// 将 URL 下载到字符串
function DownloadToString()
{
$crlf = "\r\n";

// 生成请求
$req = 'GET ' . $this->_uri . ' HTTP/1.0' . $crlf
. 'Host: ' . $this->_host . $crlf
. $crlf;

// 获取
$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);

// 拆分头部和主体
$pos = strpos($response, $crlf . $crlf);
if(
$pos === false)
return(
$response);
$header = substr($response, 0, $pos);
$body = substr($response, $pos + 2 * strlen($crlf));

// 解析头部
$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));

// 重定向?
if(isset($headers['location']))
{
$http = new HTTPRequest($headers['location']);
return(
$http->DownloadToString($http));
}
else
{
return(
$body);
}
}
}
?>
ken dot gregg at rwre dot com
20 年前
PHP 会在提供没有文件名路径的情况下打开一个目录。这个操作刚刚让我遇到问题。我之前没有检查一个串联字符串的文件名部分。

例如

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

如果 $somefile = '',则会打开目录。

如果你尝试使用文件句柄读取,你会得到二进制目录内容。我尝试了追加模式,但它会报错,所以似乎并不危险。

这是在 FreeBSD 4.5 和 PHP 4.3.1 上的表现。在 4.1.1 和 PHP 4.1.2 上表现相同。我还没有测试其他版本/操作系统组合。
bohwaz
6 个月前
请注意,你不能写入 HTTP 资源,例如进行 PUT 请求。

你会得到以下错误:'Failed to open stream: HTTP wrapper does not support writeable connections'

要执行 PUT,你只能填充 HTTP 上下文的 'content' 密钥,或者使用 Curl。
wvss at gmail dot com
2 年前
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
// 生成主机列表

function generiereHostliste($file) {

// 从 Rechnerliste.csv 读取
$fp = fopen($file, "r");
while(
$row = fgetcsv($fp, 0, ";")) {
$liste[]=[$row[0].";10.16.".$row[1].".".$row[2]];

}
fclose($fp);

// 写入 Hostliste.csv
$fp = fopen("Hostliste.csv", "w");
foreach(
$liste as $row) {
echo
"<pre>";
print_r($row);
echo
"</pre>";
fputcsv($fp, $row, ";");
}
fclose($fp);
}
// 测试
$file = "Rechnerliste.csv";
generiereHostliste($file);

?>
</body>
</html>
apathetic012 at gmail dot com
11 年前
在使用 fopen() 时,可以访问一个名为 $http_response_header 的变量,它包含一个响应头的数组。
kasper at webmasteren dot eu
12 年前
"不要使用以下保留设备名称作为文件名称
CON、PRN、AUX、NUL、COM1、COM2、COM3、COM4、COM5、COM6、COM7、COM8、COM9、LPT1、
LPT2、LPT3、LPT4、LPT5、LPT6、LPT7、LPT8 和 LPT9。 同时,也尽量避免使用以下名称
紧跟在扩展名之后;例如,NUL.txt 不建议使用。
有关更多信息,请参阅命名空间"
这是 Windows 的限制。
参见
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
flobee
18 年前
下载:我需要一个函数来模拟 "wget url",并且不将数据缓冲到内存中,以避免大型文件出现问题。
<?php
function download($file_source, $file_target) {
$rh = fopen($file_source, 'rb');
$wh = fopen($file_target, 'wb');
if (
$rh===false || $wh===false) {
// 读取或打开文件错误
return true;
}
while (!
feof($rh)) {
if (
fwrite($wh, fread($rh, 1024)) === FALSE) {
// '下载错误:无法写入文件 ('.$file_target.')';
return true;
}
}
fclose($rh);
fclose($wh);
// 无错误
return false;
}
?>
keithm at aoeex dot NOSPAM dot com
23 年前
我正在为 win32 制作一个控制台脚本,并注意到了一些事情。在 win32 上,似乎无法重新打开输入流进行读取,而必须只打开一次,然后从那里开始读取。此外,我不知道这是个错误还是什么,但似乎 fgets() 会一直读取到换行符。返回的字符数量是正确的,但它不会停止读取并返回到脚本。目前我还不知道解决方法,但我会继续研究。

这是一个解决 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
"请输入您的姓名: ";
$name=read();
echo
"请输入您的年龄: ";
$age=read();
echo
"您好 $name,今年 $age 岁感觉真好,对吧?";
@
fclose($StdinPointer);
?>
ceo at l-i-e dot com
18 年前
如果您需要对 URL 上的 fopen() 进行超时设置,您可以这样做
<?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);
// 其余部分是标准的
?>
Derrick
1 年前
以 "r+" 模式打开一个文件,然后尝试在读取文件之前使用 ftruncate 设置文件指针位置,会导致文件数据丢失,就像您以 "w" 模式打开文件一样。

例如

$File = fopen($FilePath,"r+"); // 以读写模式打开文件

ftruncate($File, 0); // 设置指针位置(会擦除数据)

while(! feof($File)) { // 继续直到到达文件末尾

$Line = fgets($File); // 将文件中的行获取到字符串中
$Line = trim($Line); // 从字符串中修剪换行符
}

ftruncate($File,0); // (不会擦除数据)

fclose($File);
k-gun at git dot io
4 年前
这里似乎没有说明,但请记住,当 $filename 包含空字节 (\0) 时,将会抛出 TypeError,消息如下;

TypeError: fopen() expects parameter 1 to be a valid path, string given in ...
wvss at gmail dot com
2 年前
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
// 生成主机列表

function generiereHostliste($file) {

// 从 Rechnerliste.csv 读取
$fp = fopen($file, "r");
while(
$row = fgetcsv($fp, 0, ";")) {
$liste[]=[$row[0].";10.16.".$row[1].".".$row[2]];

}
fclose($fp);

// 写入 Hostliste.csv
$fp = fopen("Hostliste.csv", "w");
foreach(
$liste as $row) {
echo
"<pre>";
print_r($row);
echo
"</pre>";
fputcsv($fp, $row, ";");
}
fclose($fp);
}
// 测试
$file = "Rechnerliste.csv";
generiereHostliste($file);

?>
</body>
</html>
sean downey
16 年前
在 Windows 上使用 ssl / https 时,我会遇到以下错误
"警告:fopen(https://example.com): 无法打开流:无效参数,位于 someSpecialFile.php 的第 4344534 行"

这是因为我没有启用 "php_openssl.dll" 扩展。

因此,如果您遇到同样的问题,请转到您的 php.ini 文件并启用它:)
To Top