Как заставить PHP установить правильные разрешения на загрузку файлов?

У меня есть сервер с FreeBSD 8.0, Apache 2.2.23 и PHP 5.4.10. Это моя конфигурация VirtualHost:

<VirtualHost *>
    ServerName site.com
    ServerAlias www.site.com
    DocumentRoot /usr/home/site/pub/htdocs/
    php_admin_value open_basedir /usr/home/site/
    php_admin_value session.save_path 0;0660;/usr/home/site/pub/tmp/
    php_admin_value upload_tmp_dir /usr/home/site/pub/tmp/
</VirtualHost>

/usr/home/site/pub/tmp/ принадлежит site:www с разрешением 4770. Сессионные файлы создаются корректно (660 и сайт:www). Но загруженные временные файлы создаются с правами 600. Таким образом, поскольку этот временный файл принадлежит site:www и Apache, запущенному с www:www, move_uploaded_file() не может переместить файл.

Как это исправить?

Я думаю, что мне нужен патч PHP для принудительного набора разрешений для этого файла tmp. Но где? И какая внутренняя функция в PHP может это сделать?


person BArtWell    schedule 11.01.2013    source источник
comment
Эта функция не может помочь, потому что файл, принадлежащий site:www с 600 и Apache, работающий с www:www.   -  person BArtWell    schedule 11.01.2013


Ответы (4)


Создайте файл, а затем установите разрешение, которое будет работать.

chmod("/somedir/yourfile", 0644);
person user1032531    schedule 11.01.2013
comment
Эта функция не может помочь, потому что файл, принадлежащий site:www с 600 и Apache, работающий с www:www. - person BArtWell; 11.01.2013

Не минусуйте людей, которые советуют вам использовать chmod(), потому что это единственное решение для изменения прав доступа к файлам из PHP. Однако основная проблема, по-видимому, заключается в том, что либо Apache создает файлы с другим uid, чем тот, под которым работает скрипт, [насколько маловероятно], или вы пытаетесь изменить файлы, которые были созданы с использованием другого процесса, работающего как другой пользователь.

Только владелец файла может изменить разрешение/право собственности на файл, и если отдельный процесс не запущен специально для передачи права собственности другому uid, владельцем файла является uid, создавший его.

Опять же, chmod() и chown() — это единственные два метода, с помощью которых вы можете изменить разрешения и владельца, и они эквивалентны вводу команд оболочки через exec().

person Sammitch    schedule 11.01.2013
comment
Извините, но это не мой минус. Да, ты прав. Но файлы сессий создаются корректно. Таким образом, PHP может устанавливать принудительные разрешения. Теперь я думаю, что мне нужно исправить php_open_temporary_file.c. - person BArtWell; 11.01.2013

Попробуйте посмотреть chown, вы можете временно изменить владельца файла, чтобы вы могли внести соответствующие изменения:

$File = '/path/to/file';
chown($File, USERNAMEPHPISRUNNIGNAT);
chmod($File, 0644);
// Makes Appropriate changes To Files 
chown($File, originalowner);
// Changes your file back to it's original owner

Хотите узнать, под каким именем пользователя работает php:

echo exec('whoami');

Вышеприведенное вернет пользователя, под которым работает php.

person Daryl Gill    schedule 11.01.2013

Я нашел способ исправить это. Это код моего патча:

*** main/php_open_temporary_file.c.orig 2013-01-11 20:33:42.000000000 +0400
--- main/php_open_temporary_file.c  2013-01-11 21:17:44.000000000 +0400
***************
*** 101,113 ****
    char cwd[MAXPATHLEN];
    cwd_state new_state;
    int fd = -1;
! #ifndef HAVE_MKSTEMP
!   int open_flags = O_CREAT | O_TRUNC | O_RDWR
! #ifdef PHP_WIN32
!       | _O_BINARY
! #endif
!       ;
! #endif

    if (!path || !path[0]) {
        return -1;
--- 101,107 ----
    char cwd[MAXPATHLEN];
    cwd_state new_state;
    int fd = -1;
!   int open_flags = O_CREAT | O_TRUNC | O_RDWR;

    if (!path || !path[0]) {
        return -1;
***************
*** 144,169 ****
        return -1;
    }

- #ifdef PHP_WIN32
- 
-   if (GetTempFileName(new_state.cwd, pfx, 0, opened_path)) {
-       /* Some versions of windows set the temp file to be read-only,
-        * which means that opening it will fail... */
-       if (VCWD_CHMOD(opened_path, 0600)) {
-           efree(opened_path);
-           free(new_state.cwd);
-           return -1;
-       }
-       fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600);
-   }
- 
- #elif defined(HAVE_MKSTEMP)
-   fd = mkstemp(opened_path);
- #else
    if (mktemp(opened_path)) {
!       fd = VCWD_OPEN(opened_path, open_flags);
    }
- #endif

    if (fd == -1 || !opened_path_p) {
        efree(opened_path);
--- 138,146 ----
        return -1;
    }

    if (mktemp(opened_path)) {
!       fd = VCWD_OPEN_MODE(opened_path, open_flags, 0660);
    }

    if (fd == -1 || !opened_path_p) {
        efree(opened_path);

Теперь он работает нормально, но показывает предупреждение «Предупреждение: move_uploaded_file(): операция не разрешена в /path/to/script.php в строке 111». Как подавить это предупреждение - не знаю.

person BArtWell    schedule 11.01.2013