Одинарные кавычки, изменяющие поведение в PHP - PullRequest
1 голос
/ 25 мая 2011

Я выполнял пример сценария и столкнулся с этой конкретной проблемой.

Сценарий запускается с установки

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

2 голосов
/ 25 мая 2011

Двойная кавычка - это та, которая должна оценить для вас $docroot.Единственное, что нужно сделать, это попытаться открыть файл, который на самом деле имеет $docroot в виде строки в своем пути.

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

дает тот же результат?

И используете ли вы @ для подавления ошибок?В этом случае это должно быть перед функцией, я думаю,

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

Но не делайте этого, пытаясь найти ошибки в вашем приложении.Дело в том, что вы могли очень хорошо получить ошибку, что он не может найти файл, и вы просто не заметили.

2 голосов
/ 25 мая 2011

Есть различия между одинарными и двойными кавычками в PHP.Строки в одинарных кавычках не вызывают расширение имен переменных, в то время как строки в двойных кавычках.Смотрите здесь .Почему ваш код работает, когда вы используете имя переменной со строками в одинарных кавычках, для меня не имеет смысла.Кроме того, плохая идея использовать @ перед вашими командами fopen, это не даст вам увидеть вывод ошибки.

0 голосов
/ 26 мая 2011

После моего комментария я выспался ночью и понял, что fopen() может на самом деле не использовать / быть похожим на realpath() (что предполагает установку всех сегментов, дажете, которые не имеют отношения к окончательному нормализованному пути).

Это не так.

Соответственно, причина, по которой ваш файл открыт, на самом деле довольно проста:

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

... который читается как " pastorders.txt в папке 'parts' , которая является папкой, найденной в папке выше папка '$ docroot' в текущем рабочем каталоге "сворачивается в ...

'parts/partsorders.txt'

..., потому чтоfopen() просто исчезает $docroot/.., не проверяя, существует ли $docroot.(Такие функции, как realpath(), проверьте, что меня отбросило.)

Итак, ваш файл на самом деле в <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__)), который принимает каталог файл .Пока файл знает, где он находится, вы можете просто считывать файлы относительно его местоположения.

0 голосов
/ 25 мая 2011

ОБНОВЛЕНИЕ Спасибо pinkgothic за его комментарий, во-первых, за предоставление правильной терминологии и, во-вторых, за указание, что этот ответ неправильный.
Я экспериментировал с теорией, что shell пытается расширитьПеременная окружения $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
...