fopen не работает, даже если скрипт, родительская папка и целевой файл принадлежат одному и тому же пользователю

Даже если на сервере активирован безопасный режим, если файл сценария, целевой файл и родительская папка принадлежат одному и тому же пользователю, fopen должен работать без проблем. Есть идеи, почему это происходит? Файлы имеют разрешение 755. Спасибо за ваше время и усилия.

$filename="file.html";
echo "Current User: ".get_current_user()."; UID: ".getmyuid()."; GID: ".getmygid()."<br/>";
echo "Current PID: ". getmypid() . "<br/>";
echo "Parent folder owner: ". fileowner(".") . "<br/>";
echo "$filename owner: " . fileowner($filename) . "<br/>";
echo "Current folder is writable: " . is_writable($filename);

ВЫВОД:

Текущий пользователь: vnnamp; UID: 32024; GID: 32026 Владелец родительской папки: 32024 Владелец file.html: 32024 Текущая папка доступна для записи: false


person Vishnu    schedule 28.11.2011    source источник
comment
Там четко написано: Current folder is writable: false   -  person nullpotent    schedule 28.11.2011
comment
Да, это то, что я хочу знать. Если все принадлежит одному и тому же пользователю, почему он не доступен для записи... Спасибо...   -  person Vishnu    schedule 28.11.2011


Ответы (3)


Вы уверены, что ваш скрипт работает в правильном каталоге?

Если это не так, то имя файла, которое вы передаете, скорее всего, не существует, и поэтому is_writable() возвращает false. Используйте getcwd(), чтобы распечатать каталог, в котором работает скрипт (его можно установить с помощью chdir()), или используйте абсолютные имена файлов.

РЕДАКТИРОВАТЬ: Просто подведем итоги обсуждения ниже:

  • Попробуйте абсолютный путь: Нет
  • Проверьте open-basedir в php.ini и httpd.conf: Нет
  • Попробуйте добавить к пути префикс $_SERVER['DOCUMENT_ROOT']: Нет
  • getmyuid() возвращает владельца файла скрипта, а не владельца процесса. Проверка несоответствия владельца файла и пользователя процесса с posix_getpwuid(posix_geteuid()): Да, причина проблемы
person JohnKlehm    schedule 28.11.2011
comment
Да, файл существует, так как я получаю сообщение об отказе в разрешении, когда делаю fopen для файла... - person Vishnu; 28.11.2011
comment
Попробуйте абсолютный путь? /var/www/имя_сайта/htdocs/mydir/myfile.html или аналогичный? - person JohnKlehm; 28.11.2011
comment
Только что попробовал абсолютный путь, но результат тот же: Предупреждение: fopen(/home/vnnamp/public_html/vishnu/sl/file.html) [function.fopen]: не удалось открыть поток: Отказано в доступе в ‹script_path› - person Vishnu; 28.11.2011
comment
Что такое open-basedir php.net/manual/en /ini.core.php#ini.open-basedir установлено в php.ini или httpd.conf? Вы не сможете работать с файлами вне его настроек. - person JohnKlehm; 28.11.2011
comment
В phpinfo() я вижу это в столбце Local Value: /home/vnnamp:/usr/lib/php:/usr/local/lib/php:/tmp. Так что думаю это тоже не проблема... - person Vishnu; 28.11.2011
comment
У меня нет идей, извини, приятель. :С - person JohnKlehm; 28.11.2011
comment
Я получаю те же значения, когда использую ini_get('open_basedir'). Так что он больше нигде не устанавливался... Спасибо... - person Vishnu; 28.11.2011
comment
Хех, я не мог оставить это без внимания, нашел этот фрагмент на phpnet: мне пришлось переключиться с относительных путей на полные пути, когда мой веб-хост недавно перенес сервер в свое облако хостинга. Раньше у меня это работало: ‹?php $fplog = fopen('ipn.log','a'); ?› Однако после миграции я получил следующее сообщение об ошибке: Предупреждение: fopen(ipn.log) [function.fopen]: не удалось открыть поток: Отказано в доступе в D:\home\server_name\log_test.php в строке 21. Мне пришлось изменить код на следующий, чтобы заставить его работать: ‹?php $logfile = $_SERVER['DOCUMENT_ROOT'].'\\ipn.log'; $fplog = fopen($logfile,'a'); ?› - person JohnKlehm; 28.11.2011
comment
Нет... это тоже не работает... Я думаю, проблема в том, что пользователь, под которым работает PHP, не имеет разрешения на запись в эту папку/файл. - person Vishnu; 28.11.2011
comment
Надеюсь, это все. Я думал, что getmyuid() вернет пользователя php. - person JohnKlehm; 28.11.2011
comment
Для getmyuid() php.net говорит: Получает идентификатор пользователя текущего скрипта. Так что я теперь запутался, если это владелец файла, в котором работает скрипт, или это пользователь, под которым работает PHP... - person Vishnu; 28.11.2011
comment
Другой фрагмент php.net: чтобы получить имя пользователя владельца процесса (а не владельца файла), вы можете использовать: ‹?php $processUser = posix_getpwuid(posix_geteuid()); напечатать $processUser['имя']; ?› - person JohnKlehm; 28.11.2011
comment
Подтвержденный. PHP работает под идентификатором пользователя 99. Так что это проблема, с которой я здесь столкнулся... При включенном безопасном режиме 99 сравнивается с владельцем файла, и это не удается. Итак, fopen терпит неудачу... Я думаю, что это то, что происходит. Спасибо, Джон, обсуждения с вами привели к этому... Из php.net: обратите внимание, что эта функция действительно делает то, что говорится в описании, она возвращает числовой идентификатор пользователя, который владеет файлом, содержащим текущий скрипт не является эффективным идентификатором пользователя, запускающего текущий скрипт. Большинству приложений понадобится последний вариант, который предоставляется функцией posix_getuid(). - person Vishnu; 28.11.2011
comment
Сложное имя, я понятия не имел о posix_geteuid. Рад, что теперь это решено. :) - person JohnKlehm; 28.11.2011

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

person mephisto123    schedule 28.11.2011

Результат функции is_writable() кэшируется. Попробуйте очистить его с помощью clearstatcache()

person nullpotent    schedule 28.11.2011
comment
В моем исходном сценарии я использую fopen напрямую без is_writable. Вышеприведенный скрипт предназначен только для отображения владельца всех связанных файлов/папок. - person Vishnu; 28.11.2011