Назад | Перейти на главную страницу

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

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

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

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

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

<Directory "/usr/local/myspace/webspace/httpdocs">
                PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace"
</Directory>
<VirtualHost *:80>
        ServerName damorealt.xoom.it
        DocumentRoot "/usr/local/myspace/webspace/httpdocs"
    CustomLog   /var/log/httpd/damorealt/access_log   combined
    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 read(16, "\n", 8192) = 16
25933 read(16, "", 8192)                = 0
25933 read(16, "", 8192)                = 0
25933 close(16)                         = 0

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

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

26235 time(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 read(16, "\n", 8192) = 16
26235 read(16, "", 8192)                = 0
26235 read(16, "", 8192)                = 0
26235 close(16)                         = 0
26235 uname({sys="Linux", node="svilpar4", ...}) = 0
26235 time(NULL)                        = 1278696735
26235 writev(15, [{"HTTP/1.1 200 OK\r\nDate: Fri, 09 J"..., 173},[...]
26235 chdir("/")                        = 0

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

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

Взглянув на исходный код main / main.c движка PHP 5.2.13, вы увидите:

1292:  /* Disable realpath cache if safe_mode or open_basedir are set 
*/
                if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
                        CWDG(realpath_cache_size_limit) = 0;
                }

1769: /* Disable realpath cache if safe_mode or open_basedir are set */
        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