1

サンプル スクリプトを実行していて、この特定の問題にヒットしました。

スクリプトは設定から​​始まります

 $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>
4

4 に答える 4

2

二重引用符は、評価$docrootする必要があるものです。$docroot一重引用符がすべきことは、実際にパスに文字列として含まれるファイルを開こうとすることです。する

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

同じ結果が得られますか?

そして、@エラーを抑制するために使用しますか?その場合、私が思う関数の前にあるはずです

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

ただし、アプリケーションでエラーを見つけようとするときは、そうしないでください。問題は、ファイルが見つからず、気付かないというエラーが発生する可能性が非常に高いということです。

于 2011-05-25T16:22:34.503 に答える
2

PHP では、一重引用符と二重引用符で囲まれた文字列に違いがあります。単一引用符で囲まれた文字列は変数名を展開しませんが、二重引用符で囲まれた文字列は展開します。ここを参照してください。一重引用符で囲まれた文字列で変数名を使用するときにコードが機能する理由は、私には意味がありません。さらに、@fopen コマンドの前に使用するのはお勧めできません。エラー出力が表示されなくなります。

于 2011-05-25T16:21:22.863 に答える
0

私のコメントの後、私は一晩眠りましたfopen()が、実際には使用しない/似ている可能性があることに気付きrealpath()ました(最終的な正規化されたパスに関係のないものであっても、すべてのセグメントが設定されることを期待しています)。

そうではありません。

したがって、ファイルが開かれる理由は実際にはかなり単純です。

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

...「現在の作業ディレクトリにある'$docroot'フォルダーののフォルダーにある'parts'フォルダー内のpastorders.txtとして読み取られる」は、次のように折りたたまれます...

'parts/partsorders.txt'

...存在を確認せずにfopen()単に消えてしまうからです。( do check it のような関数は、私をうんざりさせていました。)$docroot/..$docrootrealpath()

したがって、ファイルは実際には<current working directory>/parts/partsorders.txt. (フラグを付けてファイルを開いているため、a以前に存在しなかった場合は、間違いなくそこに作成されています。)

内容が何であれ$_SERVER['DOCUMENT_ROOT']、それはあなたが望むものではないようです。さらに、一部のセットアップでは、合理的..に上記を行うことはできません$_SERVER['DOCUMENT_ROOT']- パーミッションは実際には許可しません。

その環境変数が完全に設定されていない場合 (それが可能である場合でも、そうでない場合でもこれは問題を示していると思います)、パスはまったく異なります。

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

...次のようになります:

"/../parts/partsorders.txt"

...これは、ルート ポイント ( ) を超えて階層を上げようとします/が、もちろんうまくいきません。

エコーアウトまたはログ$_SERVER['DOCUMENT_ROOT']に記録して、実際に何が含まれているかを確認し、それが期待どおりかどうかを確認することをお勧めします。

探す価値があるのは(または__DIR__古い PHP バージョンではdirname(__FILE__)) で、これはディレクトリのファイルを受け取ります。ファイルがその場所を認識している限り、その場所に関連するファイルを読み取ることができます。

于 2011-05-26T08:18:09.723 に答える
0

更新 彼のコメントに対してpinkgothicに感謝します.1つ目は正しい用語を提供し、2つ目はこの答えが間違っていることを指摘してくれた.
シェルが環境変数を展開しようとしているという理論を試して$docrootみたところ、 ではシェル展開ができないことがわかりました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()、私の答えは、私が言うように間違っています。


文字列$docroot/../parts/partsorders.txtは、オペレーティング システムのシェルに直接送信されています。変数が設定されていない$docrootため、空の文字列に置き換えられるため、使用するのと同じです

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

/これは、ドキュメント ルートであるから始まる絶対パスです。

#run from shell (bash)
~$ echo $docroot/../parts/partsorders.txt
/../parts/partsorders.txt
于 2011-05-25T16:29:29.330 に答える