Безопасный режим 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" Directory> Имя_сервера damorealt.xoom.it DocumentRoot "/ usr / local / myspace / webspace / httpdocs "CustomLog / var / log / httpd / damorealt / access_log в сочетании ErrorLog / var / log / httpd / damorealt / error_log VirtualHost>
На странице вызова 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