PHP 中的单引号反转行为

发布于 2024-11-09 19:55:19 字数 1092 浏览 5 评论 0原文

我正在运行一个示例脚本并遇到了这个特定问题。

该脚本首先设置

 $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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

够运 2024-11-16 19:55:19

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.

べ繥欢鉨o。 2024-11-16 19:55:19

双引号应该为您评估 $docroot 。单引号应该做的是尝试打开一个文件,该文件的路径中实际上有 $docroot 作为字符串。 吗

@$fp = fopen($docroot . '/../parts/partsorders.txt','ab');

会产生相同的结果

?您是否使用 @ 来抑制错误?在这种情况下,它应该在我认为的函数之前

$fp = @fopen($docroot . '/../parts/partsorders.txt','ab');

,但在尝试查找应用程序中的错误时不要这样做。问题是,您很可能会收到一个错误,指出找不到该文件,而您只是没有注意到。

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. Does

@$fp = fopen($docroot . '/../parts/partsorders.txt','ab');

yield the same result?

And do you use @to supress errors? In that case it should be before the function I think

$fp = @fopen($docroot . '/../parts/partsorders.txt','ab');

But 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.

冷︶言冷语的世界 2024-11-16 19:55:19

更新
感谢 Pinkgothic 的评论,首先感谢他提供了正确的术语,其次感谢他指出这个答案是错误的。
我尝试了 shell 试图扩展环境变量 $docroot 的理论,发现 shell 扩展在 fopen() 中是不可能的。
我尝试了以下代码并收到此错误(我的主目录中有一个名为 test.txt 的文件)

$fp = fopen( '$HOME/test.txt', 'rb' );
//PHP Warning:  fopen($HOME/test.txt): failed to open stream: No such file or directory in php shell code on line 1

所以除非 OP 有一些允许在 fopen() 中进行 shell 扩展的配置,否则我的答案是,正如我所说,不正确。


字符串 $docroot/../parts/partsorders.txt 被直接发送到操作系统 shell。由于没有设置 $docroot 变量,因此它被替换为空字符串,因此它与使用

@$fp = fopen('/../parts/partsorders.txt','ab');

Which is a绝对路径(从文档根 / 开始)相同。

#run from shell (bash)
~$ echo $docroot/../parts/partsorders.txt
/../parts/partsorders.txt

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 in fopen().
I tried the following code and got this error (I have a file called test.txt in my home directory)

$fp = fopen( '$HOME/test.txt', 'rb' );
//PHP Warning:  fopen($HOME/test.txt): failed to open stream: No such file or directory in php shell code on line 1

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 using

@$fp = fopen('/../parts/partsorders.txt','ab');

Which is an absolute path starting from /, the document root.

#run from shell (bash)
~$ echo $docroot/../parts/partsorders.txt
/../parts/partsorders.txt
自此以后,行同陌路 2024-11-16 19:55:19

在我发表评论后,我睡了一晚,意识到 fopen() 可能实际上并没有使用/be like realpath() (它期望设置所有段,甚至是那些与最终标准化路径无关)。

事实并非如此。

因此,打开文件的原因实际上相当简单:

'$docroot/../parts/partsorders.txt'

...读作“pastorders.txt 'parts'文件夹中,该文件夹位于'$docroot'文件夹的上面的文件夹中,该文件夹位于 >当前工作目录”折叠到...

'parts/partsorders.txt'

...因为fopen() 只是将 $docroot/.. 消失,而不检查 $docroot 是否存在。 (像 realpath() 这样的函数确实会检查它,这让我很失望。)

所以,您的文件实际上位于 <当前工作目录>/parts/partsorders.txt 中。 (由于您使用 a 标志打开文件,因此如果该文件之前不存在,则肯定是在该文件中创建的。)

无论您的 $_SERVER['DOCUMENT_ROOT' ]包含,看来这不是你想要的。此外,在某些设置中,您无法合理地 .. 高于 $_SERVER['DOCUMENT_ROOT'] - 权限实际上不允许您这样做。

如果该环境变量完全没有设置(如果这是可能的;但我认为这说明了问题,即使它不是),路径是完全不同的:

"$docroot/../parts/partsorders.txt"

...变成:

"/../parts/partsorders.txt"

.. .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 like realpath() (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:

'$docroot/../parts/partsorders.txt'

...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...

'parts/partsorders.txt'

...because fopen() simply vanishes $docroot/.. away without checking that $docroot exists. (Functions like realpath() 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 the a 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:

"$docroot/../parts/partsorders.txt"

...becomes:

"/../parts/partsorders.txt"

...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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文