如果文件不存在,PHP fopen() 不创建文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5160362/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 16:59:12  来源:igfitidea点击:

PHP fopen() not creating file if it doesn't already exist

php

提问by b. e. hollenbeck

As part of application logging, I'm attempting to open a local file, and if that file doesn't already exist, to create the new one. Here's what I have:

作为应用程序日志记录的一部分,我试图打开一个本地文件,如果该文件不存在,则创建新文件。这是我所拥有的:

$path = '/home/www/phpapp/logs/myawesome_logfile.txt';
$f = (file_exists($path))? fopen($path, "a+") : fopen($path, "w+");
fwrite($f, $msg);
fclose($f);
chmod($path, 0777);

I've double-checked, and the /logsdirectory is chmod 0777, and I even went the extra step of chown'ing it to apache:apache for good measure. Still, when the script goes to open the file, it gives me the warning that the file doesn't exist and bombs out. No file is ever created.

我已经仔细检查过,该/logs目录是 chmod 0777,我什至采取了额外的步骤,将其 chown'ing 到 apache:apache 以进行良好的衡量。尽管如此,当脚本打开文件时,它会警告我该文件不存在并爆炸。没有文件被创建。

Do I need to suppress the fopen()warning to get it to create the file?

我是否需要取消fopen()警告才能创建文件?

回答by Daniel Bingham

When you're working with paths in PHP, the context can matter a great deal. If you're working with urls in a redirection context -- then the root directory ('/') refers to your domain's root. The same goes for paths for linking files or images and for include and require directives.

当您在 PHP 中使用路径时,上下文可能非常重要。如果您在重定向上下文中使用 url,那么根目录 ('/') 是指您的域的根目录。链接文件或图像的路径以及包含和要求指令的路径也是如此。

However, when you're dealing with file system commands such as fopen, the root directory ('/') is the system root. Not your domain root.

但是,当您处理诸如 之类的文件系统命令时fopen,根目录 ('/') 是系统根目录。不是您的域根。

To fix this, try giving the full path to the log file you want to open from the system root. For example: /var/www/phpapplication/logs/myLogFile.txt

要解决此问题,请尝试提供要从系统根目录打开的日志文件的完整路径。例如:/var/www/phpapplication/logs/myLogFile.txt

Or you could use $_SERVER['DOCUMENT_ROOT']as suggested in other answers to access your server's stored value for the path to the document root. The /var/wwwpart.

或者,您可以$_SERVER['DOCUMENT_ROOT']按照其他答案中的建议使用来访问服务器存储的文档根路径的值。的/var/www一部分。

You can also use the __DIR__magic constant in some cases. Note that __DIR__will be the directory the current file is in, which is not necessarily the same as your application's root. So for example, if your application's root is /var/www/applicationand you're working in /var/www/application/src/controllers/my_controller.php, then __DIR__will be /var/www/application/src/controllers. See here in the PHP documentation.

__DIR__在某些情况下,您还可以使用魔术常量。请注意,这__DIR__将是当前文件所在的目录,它不一定与您的应用程序的根目录相同。因此,例如,如果您的应用程序的根是/var/www/application并且您正在使用/var/www/application/src/controllers/my_controller.php,那么__DIR__将是/var/www/application/src/controllers请参阅 PHP 文档中的此处。

回答by Tobias

Have you tried this?

你试过这个吗?

$msg = "I'm a line that is a message.\n";
$path = $_SERVER['DOCUMENT_ROOT'] . '/logs/myawesome_logfile.txt';
$f = fopen($path, "a+");
fwrite($f, $msg);
fclose($f);
chmod($path, 0777);

The server you're working on could have jailed you to only work in the phpapp's directory and its subdirectories.

您正在使用的服务器可能会让您只能在 phpapp 的目录及其子目录中工作。

回答by Miguel

One way I got around this problem in UBUNTU 14.04 was by right clicking on the directory where the file is located and changing the permissions of "others" to "create and delete files".

我在 UBUNTU 14.04 中解决这个问题的一种方法是右键单击文件所在的目录并将“其他人”的权限更改为“创建和删除文件”。

回答by Your Common Sense

You can always open your file with just "a", it will create a new file as well.
No need to make a condition.

您可以随时使用 just 打开文件"a",它也会创建一个新文件。
没必要做条件。

However, the main issue with your code is understanding the difference between physical filesystem and virtual web-server, which have been perfectly explained already.

但是,您的代码的主要问题是理解物理文件系统和虚拟网络服务器之间的区别,这已经得到了完美的解释。

Note that you should provide your question with exact copy of error message. It contains a ton of extremely useful information, it's not like an oath "I won't create your file, go away!" but it's through explanation of what and why is going wrong. If you don't care of such useful info yourself, you have to provide it to ones whom asking for help.

请注意,您应该向问题提供错误消息的准确副本。它包含了大量非常有用的信息,这不像是一句“我不会创建你的文件,滚开!”的誓言。但它是通过解释什么和为什么出了问题。如果您自己不关心这些有用的信息,则必须将其提供给寻求帮助的人。

回答by Jose Manuel Blasco Galdón

The path of the file must be with the server root. I could achieve this using the phpinfo() method inside the document I wanted to know. So when you use phpinfo() you will see a information document. If you find for _SERVER["SCRIPT_FILENAME"] you will see the absolute path of your file.

文件的路径必须是服务器根目录。我可以使用我想知道的文档中的 phpinfo() 方法来实现这一点。因此,当您使用 phpinfo() 时,您将看到一个信息文档。如果您找到 _SERVER["SCRIPT_FILENAME"] ,您将看到文件的绝对路径。

I hope this help someone.

我希望这对某人有帮助。

回答by Murky Master

Don't forget to make sure that SELinux isn't blocking you.

不要忘记确保 SELinux 没有阻止您。

[root@yourbox]# audit2allow < /var/log/audit/audit.log
#============= httpd_t ==============
#!!!! This avc can be allowed using the boolean 'httpd_unified' allow httpd_t httpd_sys_content_t:dir { write add_name };
#!!!! This avc can be allowed using the boolean 'httpd_unified' allow httpd_t httpd_sys_content_t:file { write create }; [root@yourbox]# audit2allow -a -M my_httpd

[root@yourbox]# audit2allow < /var/log/audit/audit.log
#============== httpd_t ==============
#!! !! 可以使用布尔值 'httpd_unified' 允​​许该 avc 允许 httpd_t httpd_sys_content_t:dir { write add_name };
#!!!!!! 可以使用布尔值 'httpd_unified' 允​​许此 avc 允许 httpd_t httpd_sys_content_t:file { write create }; [root@yourbox]# audit2allow -a -M my_httpd

Note:

笔记:

To make this policy package active, execute:

要激活此策略包,请执行:

semodule -i my_httpd.pp

[root@yourbox]# semodule -i my_httpd.pp
[root@yourbox]# systemctl restart httpd

semodule -i my_httpd.pp

[root@yourbox]# semodule -i my_httpd.pp
[root@ yourbox ]# systemctl restart httpd