Безопасный режим PHP /open_basedir - проблема производительности lstat

PHP lstat полный путь много раз, прежде чем читать файл ищет. И это происходит, когда в конфигурации apache httpd указана настройка open_basedir PHP_ADMIN_VALUE или если параметр safe_mode включен.

Если у меня есть простой веб-сайт со страницей только phpinfo.php, а внутри у нас только "".

Представьте, что у нас последняя версия httpd (2.2.15) и PHP (5.2.13 или 5.3.2).

Если мы указываем safe_mode = on или PHP_ADMIN_VALUE open_basedir в конфигурации виртуального хоста:

 PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace" Имя_сервера damorealt.xoom.it DocumentRoot "/ usr / local / myspace / webspace / httpdocs "CustomLog / var / log / httpd / damorealt / access_log в сочетании ErrorLog / var / log / httpd / damorealt / error_log

На странице вызова http://damorealt.xoom.it/phpinfo.php мы можем воспроизвести следующее поведение:

Первая проверка

25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0

Вторая проверка

25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0

Третья проверка (неполная)

25933 lstat ("/ usr", {st_mode = S_IFDIR | 0755, st_size = 4096,...}) = 0
25933 lstat ("/ usr / local", {st_mode = S_IFDIR | 0755, st_size = 4096,...}) = 0
25933 lstat ("/ usr / local / myspace", {st_mode = S_IFDIR | 0755, st_size = 4096,...}) = 0
25933 lstat ("/ usr / local / myspace / webspace", {st_mode = S_IFDIR | 0755, st_size = 4096,...}) = 0

Пятая проверка.

25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0

Прочитайте файл!

25933 open ("/ usr / local / myspace / webspace / httpdocs / phpinfo.php", O_RDONLY) = 16 25933 fstat (16, {st_mode = S_IFREG | 0644, st_size = 16,...}) = 0 25933 чтения (16, "\n", 8192) = 16
25933 чтения (16, "", 8192)                = 0
25933 чтения (16, "", 8192)                = 0
25933 закрытие (16)                         = 0

Если PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace" удален::

Первая проверка

26235 раз (NULL)                        = 1278696735
26235 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
26235 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
26235 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
26235 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
26235 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
26235 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0

Прочитайте файл.

26235 open ("/ usr / local / myspace / webspace / httpdocs / phpinfo.php", O_RDONLY) = 16
26235 fstat (16, {st_mode = S_IFREG | 0644, st_size = 16,...}) = 0
26235 читать (16, "\n", 8192) = 16
26235 читать (16, "", 8192)                = 0
26235 читать (16, "", 8192)                = 0
26235 закрыть (16)                         = 0
26235 uname({sys="Linux", node="svilpar4", ...}) = 0
26235 раз (NULL)                        = 1278696735
26235 writev(15, [{"HTTP/1.1 200 OK\r\nDate: Fri, 09 J"..., 173},[...]
26235 chdir("/")                        = 0

Может кто-нибудь объяснить мне, почему в PHP такое поведение?

1 ответ

Решение

Кеш реального пути отключается, если установлены safe_mode или open_basedir. Это резко снижает производительность PHP Engine, и такое поведение может поставить сервер на колени. Тем более, что не хватает документации!

Глядя на исходный код main / main.c PHP-движка 5.2.13, вы можете увидеть:

1292: / * Отключить кеш реального пути, если установлены safe_mode или open_basedir 
*/
                if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
                        CWDG(realpath_cache_size_limit) = 0;
                }

1769: /* Отключить кеш реального пути, если установлены safe_mode или open_basedir * /
        if (PG (safe_mode) || (PG (open_basedir) && * PG (open_basedir))) {
                CWDG (realpath_cache_size_limit) = 0;
        }

Пожалуйста, обратитесь к: http://bugs.php.net/bug.php?id=52312

Обходное решение описано здесь:https://github.com/Whissi/realpath_turbo

с этим расширением вы можете использовать кеш realpatch с включенным openbasedir

Другие вопросы по тегам