Заметив некоторое замедление работы PHP на постоянных проверках lstat всех путей открываемых файлов и директорий, решил поднастроить производительность, увеличив realpath_cache_size. Был немного удивлён, когда получил из
var_dump(realpath_cache_size(),realpath_cache_get());

int(0); array(0) {}


Ещё больше удивило, что этот баг до сих пор не решён в последних версиях PHP 5.6, а в документации про него ни слова (один комментарий пользователя месяц назад).

Некоторым гуглением было найдено решение: расширение, совмещающее в себе open_basedir и работающее через кеш путей php. Turbo_realpath.

В Pecl его нет, поэтому скачиваем архив с офсайта (для версий 5.4+, ниже смотрите на офсайте).

Установка в консоли:
unzip realpath_turbo_1.2.zip
cd realpath_turbo
phpize
./configure
make
make install


В php.ini или как, например, у меня в debian-like, для отдельного расширения своя конфигурация:
extension=turbo_realpath.so


заменяем настройки open_basedir
# clear all open_basedir restrictions
open_basedir=""
# replace it with 
realpath_cache_basedir = /var/www/html/drupal


Расширение может ещё некоторые security улучшения:
; set this to 1 in order to disable dangerous PHP functions (link,symlink), or set to 0 in order to ignore potential security issues
<video></video>; установка в 1 чтобы отключить опасные PHP функции (link,symlink), или в 0 чтобы проигнорировать потенциально опасные вещи
realpath_cache_security = 1
; if you want, you can enable safe_mode, in order to do so, you have to switch off
; standard open_basedir setting...
; если хотите, можете включить safe_mode, в свою очередь, вы должны отключить стандартный open_basedir
open_basedir = off
; and then switch on custom realpath_cache_open_basedir setting,
; (remember, safe mode is not required by realpath_turbo extension, 
; you can safely ignore these settings if you want)
; и тогда включить кастомный realpath_cache_open_basedir
; (помните, safe mode не требуется для расширения realpath_turbo, вы можете спокойно игнорировать эту опцию, если хотите)
real_path_cache_safe_mode = on

Комментарии (14)


  1. turone
    08.11.2015 23:13
    +2

    Ещё бы показательно было насколько помогло — была задержка такая то, теперь такая то, интересует эффективность расширения на вашем примере.


    1. romy4
      09.11.2015 12:38

      Вот на примере Друпала показательней всего, для чего так необходим realpath_cache. Плюс уменьшение cpu load и обращений к диску даже на небольших проектах, когда их много, в сумме даёт прирост производительности.


  1. nitso
    08.11.2015 23:19
    +2

    Странное чувство не покидает меня после прочтения этой статьи.

    Баг относится во-первых еще к версии 5.2, а во-вторых к включенному режиму safe_mode. Safe_mode выпилили еще пару лет назад (в 5.4 [раз] [два]). А вы рассказываете про решение этого бага в 5.6. Каша какая-то.


    1. b1rdex
      09.11.2015 04:20
      +1

      Если задан open_basedir, то кэш тоже не работает. Насколько я понял, автору необходима эта настройка + кэш путей.


      1. nitso
        09.11.2015 11:57

        Меня смущает только то, что во всех найденых упоминаниях этого бага присутствует safe_mode. А основной задачей указанного в статье модуля является возвращение safe_mode в последние версии php: «This version adds support for safe_mode = on setting.»


        1. romy4
          09.11.2015 12:14

          Нет, задача стояла убрать постоянные обращения lstat в проверке путей мимо кеша realpath_cache. То, что он может включать safe_mode — это уже побочные фичи. Главное, что свою задачу он решает. В багрепорте Safe_mode упоминается лишь потому, что он оказывает такое же влияние на realpath_cache, как и open_basedir.


          1. nitso
            09.11.2015 13:25

            Перепроверил еще раз — при включенной опции open_basedir realpath_cache_size() действительно возвращает ноль. Не могу никак найти обработку open_basedir в контексте realpath_cache в исходниках.

            Однако, если вы говорите о lstat как о функции PHP, а не о системном вызове
            По выводу realpath_cache_size() нельзя делать выводы о кэше lstat()stat()), потому как для них реализованы два разных механима кэширования (в исходнике clearstatcache видно более наглядно). Вызов lstat() и без open_basedir не помещает значений в кэш realpath. Короткий тест на корректное функционирование кэша lstat:

            <?php
            // обновляем mtime временного файла текущей датой
            touch("./tmp");
            var_dump(lstat("./tmp")["mtime"]);
            
            // обновляем mtime "задним числом"
            touch("./tmp", 1347062644);
            var_dump(lstat("./tmp")["mtime"]);
            
            // очищаем кэш и проверяем результат
            clearstatcache();
            var_dump(lstat("./tmp")["mtime"]);
            

            $ php test.php                                
            int(1447062787)
            int(1447062787)
            int(1347062644)

            $ php -dopen_basedir="." test.php             
            int(1447062797)
            int(1447062797)
            int(1347062644)


            1. romy4
              09.11.2015 13:40

              Не, идёт речь не про вызов php обёртки lstat, а именно системный lstat(), который наблюдается в логе strace.


  1. FractalizeR
    09.11.2015 10:50

    Кстати, вот тут есть объяснение, почему это до сих пор не «пофиксили».


    1. romy4
      09.11.2015 12:19
      +1

      Если честно, то странное объяснение. Open_basedir не даёт 100% гарантии, что юзер не откроет каким-то способом файл за пределами ограничений open_basedir. Остаётся вопрос, зачем вы тогда вообще сделали такую опцию? В общем, внятного ответа, почему не хотят исправить баг нет.


      1. FractalizeR
        09.11.2015 14:06

        Open_basedir не даёт 100% гарантии, что юзер не откроет каким-то способом файл за пределами ограничений open_basedir

        Можно поподробнее? Что вы имеете ввиду?


        1. romy4
          09.11.2015 15:09

          Только то, что написано по вашей ссылке в комментарии: «An open_basedir feature that doesn't actually guarantee that users can't open files outside of the specified base directory isn't useful.» Короче, я не очень понял Расмуса с его объяснением. Ну да, нельзя гарантировать, что файл не изменится, пока путь будет в кеше (это очевидно). Он типа не видит смысла в open_basedir, если каким-то образом решится аспект безопасности (наверное, про изменения вне кеша).


          1. FractalizeR
            09.11.2015 15:47

            Он имеет ввиду, что если сделать так, как предлагает этот реквест, то open_basedir перестанет иметь смысл, поскольку будет небезопасен.


  1. FractalizeR
    09.11.2015 14:06

    удалено