PHP 中的单引号反转行为
我正在运行一个示例脚本并遇到了这个特定问题。
该脚本首先设置
$docroot=$_SERVER['DOCUMENT_ROOT'];
“用于写入文件”,
@$fp = fopen("$docroot/../parts/partsorders.txt",'ab');
使用。但无论如何,这都无法写入文件。
经过一段时间的修改后,我将命令设置为
@$fp = fopen('$docroot/../parts/partsorders.txt','ab');
使用单引号而不是双引号,并且效果很好!
我的问题是,以前的双引号格式不应该代替单引号吗?这里发生了什么事?
伙计们,这是精简的代码(假设该文件存在于服务器中):
<?php
$docroot=$_SERVER['DOCUMENT_ROOT'];
$outputstring = "herpderp";
?>
<html>
<head>
<title>Quotes</title>
</head>
<body>
<?php
@$fp=fopen("$docroot/../parts/partsorders.txt","ab");
flock($fp, LOCK_EX);
if(!$fp) {
echo "<p><strong>Failed.</strong></p></body></html>";
exit;
}
fwrite($fp,$outputstring,strlen($outputstring));
flock($fp,LOCK_UN);
fclose($fp);
echo "<p>Order written.</p>";
?>
</body>
</html>
I was running over a sample script and hit on this particular issue.
The script starts off by setting
$docroot=$_SERVER['DOCUMENT_ROOT'];
For writing to a file,
@$fp = fopen("$docroot/../parts/partsorders.txt",'ab');
is used. But no matter what, this fails to write to the file.
After a tinkering with it for a while, I set the command to
@$fp = fopen('$docroot/../parts/partsorders.txt','ab');
used single quotes instead of double quotes and it worked fine!
My question is, isn't the former double quoted format supposed to work instead of the single quotes. What is happening here ?
Here is the stripped down code, guys (Assume that the file exists in the server) :
<?php
$docroot=$_SERVER['DOCUMENT_ROOT'];
$outputstring = "herpderp";
?>
<html>
<head>
<title>Quotes</title>
</head>
<body>
<?php
@$fp=fopen("$docroot/../parts/partsorders.txt","ab");
flock($fp, LOCK_EX);
if(!$fp) {
echo "<p><strong>Failed.</strong></p></body></html>";
exit;
}
fwrite($fp,$outputstring,strlen($outputstring));
flock($fp,LOCK_UN);
fclose($fp);
echo "<p>Order written.</p>";
?>
</body>
</html>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
PHP 中单引号和双引号字符串之间存在差异。单引号字符串不会导致变量名称扩展,而双引号字符串则会导致变量名称扩展。请参阅此处。为什么当您使用带单引号字符串的变量名时您的代码可以工作,这对我来说没有意义。此外,在 fopen 命令前面使用
@
是一个坏主意,它会阻止您看到错误输出。There are differences between single and double quoted strings in PHP. Single quoted strings do not cause the expansion of variable names while double quoted strings do. See here. Why your code works when you use the variable name with single quoted strings doesn't make sense to me. Furthermore, it's a bad idea to use
@
in front of your fopen commands, it will prevent you from seeing the error output.双引号应该为您评估
$docroot
。单引号应该做的是尝试打开一个文件,该文件的路径中实际上有$docroot
作为字符串。 吗会产生相同的结果
?您是否使用
@
来抑制错误?在这种情况下,它应该在我认为的函数之前,但在尝试查找应用程序中的错误时不要这样做。问题是,您很可能会收到一个错误,指出找不到该文件,而您只是没有注意到。
The double quote one is the one that should evaluate
$docroot
for you. What the single quote should do is try to open a file that actually has$docroot
as a string in it's path. Doesyield the same result?
And do you use
@
to supress errors? In that case it should be before the function I thinkBut don't do that when trying to find errors in your application. The thing is that you could very well get an error that it can't find the file and you just don't notice.
更新
感谢 Pinkgothic 的评论,首先感谢他提供了正确的术语,其次感谢他指出这个答案是错误的。
我尝试了 shell 试图扩展环境变量
$docroot
的理论,发现 shell 扩展在fopen()
中是不可能的。我尝试了以下代码并收到此错误(我的主目录中有一个名为 test.txt 的文件)
所以除非 OP 有一些允许在
fopen()
中进行 shell 扩展的配置,否则我的答案是,正如我所说,不正确。字符串
$docroot/../parts/partsorders.txt
被直接发送到操作系统 shell。由于没有设置$docroot
变量,因此它被替换为空字符串,因此它与使用Which is a绝对路径(从文档根
/
开始)相同。UPDATE
Thanks to pinkgothic for his comment, firstly for providing the correct terminology and secondly for pointing out that this answer is wrong.
I have experimented with the theory that shell is trying to expand the environment variable
$docroot
and found that shell expansion is not possible infopen()
.I tried the following code and got this error (I have a file called test.txt in my home directory)
So unless the OP has some configuration which allows shell expansion in
fopen()
, my answer is, as I say, incorrect.The string
$docroot/../parts/partsorders.txt
is being sent directly to the operating system shell. As there is no$docroot
variable set it is replaced by an empty string, so it is the same as usingWhich is an absolute path starting from
/
, the document root.在我发表评论后,我睡了一晚,意识到
fopen()
可能实际上并没有使用/be likerealpath()
(它期望设置所有段,甚至是那些与最终标准化路径无关)。事实并非如此。
因此,打开文件的原因实际上相当简单:
...读作“pastorders.txt 在'parts'文件夹中,该文件夹位于'$docroot'文件夹的上面的文件夹中,该文件夹位于 >当前工作目录”折叠到...
...因为
fopen()
只是将$docroot/..
消失,而不检查$docroot
是否存在。 (像realpath()
这样的函数确实会检查它,这让我很失望。)所以,您的文件实际上位于
<当前工作目录>/parts/partsorders.txt
中。 (由于您使用a
标志打开文件,因此如果该文件之前不存在,则肯定是在该文件中创建的。)无论您的
$_SERVER['DOCUMENT_ROOT' ]
包含,看来这不是你想要的。此外,在某些设置中,您无法合理地..
高于$_SERVER['DOCUMENT_ROOT']
- 权限实际上不允许您这样做。如果该环境变量完全没有设置(如果这是可能的;但我认为这说明了问题,即使它不是),路径是完全不同的:
...变成:
.. .which 尝试将层次结构提升到根点 (
/
) 之上,这当然是行不通的。我建议回显或记录
$_SERVER['DOCUMENT_ROOT']
并查看它实际包含的内容,以及是否是您期望的内容。可能值得寻找的是
__DIR__
(或者在较旧的 PHP 版本中,dirname(__FILE__)
),它将目录文件。只要文件知道它在哪里,您就可以读出相对于其位置的文件。After my comment, I had a night's sleep and realised
fopen()
may not actually use/be likerealpath()
(which expects all segments to be set, even the ones that are irrelevant for the final normalised path).It doesn't.
Accordingly, the reason your file is opened is actually fairly simple:
...which is read as "pastorders.txt in the 'parts' folder which is a folder found in the folder above the '$docroot' folder which is in the current working directory" collapses to...
...because
fopen()
simply vanishes$docroot/..
away without checking that$docroot
exists. (Functions likerealpath()
do check it, which was throwing me off.)So, your file is actually in
<current working directory>/parts/partsorders.txt
. (Since you're opening the file with thea
flag, if it didn't exist there before, it was definitely created there.)Whatever your
$_SERVER['DOCUMENT_ROOT']
contains, it seems it's not what you want. Additionally, in some setups, you can't reasonably..
above$_SERVER['DOCUMENT_ROOT']
- permissions actually won't let you.If that environment variable outright isn't set (if that's even possible; but I think this demonstrates the problem even if it isn't), the path is quite different:
...becomes:
...which tries to get up the hierarchy past the root point (
/
), which would of course not work.I suggest echoing out or logging
$_SERVER['DOCUMENT_ROOT']
and taking a look at what it actually contains, and if it's what you expect it to be.What might be worth looking for is
__DIR__
(or in older PHP versions,dirname(__FILE__)
), which takes the directory the file. As long as the file knows where it is, you can just read out files relative to its location.