Это явно не заслуживает отдельной статьи на Хабре, но ошибка может коснуться большого количества людей, поэтому я всё-таки решил написать.


http://php.net/manual/en/configuration.file.php#configuration.file.changelog :


7.0.0 Hash marks (#) are no longer recognized as comments.

Казалось бы, что такого? Админы на тестовом сервере обнаружат появившиеся ошибки в конфигах и быстро поправят. Но тут вступает в дело одна неприятная особенность php-fpm: он отказывается запускаться с некорректным файлом php-fpm.conf, но спокойно запустится с некорректным php.ini, проигнорировав все его настройки и используя значения по умолчанию. Ошибка не будет видна в консоли, так как её проглотит скрипт запуска службы, и не будет записана в лог php-fpm.



Если php.ini был скопирован из пятой версии, а более строгий парсер седьмой читает его с ошибками — php-fpm будет молча работать со значениями по-умолчанию. Например, если там использовались # для комментариев и такой комментарий содержит открывающую скобку. Без открывающей скобки он такие комментарии по-прежнему воспринимает нормально, несмотря на объявление в changelog.


Максимальный объём загружаемого файла post_max_size=8m, включен expose_php, передающий в заголовке X-Powered-By используемую версию PHP, станет пустой disable_functions, используемая для отключения потенциально небезопасных функций, display_errors станет 1 и посетители увидят полный стектрейс на страницах с ошибками, и ещё много всего весёлого.


Мейнтейнеры PHP в Ubuntu пытаются обходить эту особенность с помощью костыля:


/etc/systemd/system/multi-user.target.wants/php7.0-fpm.service:

...
ExecStartPre=/usr/lib/php/php7.0-fpm-checkconf
...

/usr/lib/php/php7.0-fpm-checkconf:

...
errors=$(/usr/sbin/php-fpm7.0 --fpm-config "$CONFFILE" -t 2>&1 | grep "\[ERROR\]" || true);
...

Но костыль не работает:


root@xenial:~# /usr/sbin/php-fpm7.0 --fpm-config  /etc/php/7.0/fpm/php-fpm.conf --test
PHP:  syntax error, unexpected '(' in /etc/php/7.0/fpm/php.ini on line 6
[14-Sep-2016 14:24:46] NOTICE: configuration file /etc/php/7.0/fpm/php-fpm.conf test is successful

root@xenial:~# /usr/lib/php/php7.0-fpm-checkconf; echo $?
0

Пакет php7.0-fpm из популярного ppa:ondrej/php, откуда обычно ставят PHP 7 на сервера с ubuntu trusty или precise, вообще не содержит такой проверки.


Итого: если вы обновляетесь c PHP 5 на PHP 7, убедитесь, что он не проигнорировал настройки в php.ini и не завёлся со значениями по-умолчанию.


P.S.
» Тикет для ppa:ondrej/php
» Тикет для php7.0-fpm в ubuntu xenial


UPD: По просьбе в комментариях запостил баг разработчикам PHP: 73099

Поделиться с друзьями
-->

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


  1. youlose
    16.09.2016 07:19
    +10

    Если php.ini был скопирован из пятой версии
    При чём тут Ubuntu Xenial, если вы скопировали этот файл вручную?
    На убунте пхп 7 имеет отдельные папки для конфигов и она создаёт там новые конфиги при установке.


    1. imgen
      16.09.2016 09:51

      Именно тот случай, где сделали — то, чего нельзя было делать и изобрели к нему костыли. К тому же у xenial по умолчанию стоят ppa не от ondrej/php.


      1. selivanov_pavel
        16.09.2016 12:44

        К тому же у xenial по умолчанию стоят ppa не от ondrej/php.

        Проблема воспроизводится и в официальных пакетых от убунты, и в пакетах из ondrej/php.


    1. selivanov_pavel
      16.09.2016 12:42

      При чём тут Ubuntu Xenial, если вы скопировали этот файл вручную?

      У нас этот файл раскладывается ролью ansible, и при переделывании роли с php5 на php7 я его просто скопировал и проверил по документации, что все используемые директивы работают так же. Вне зависимости от используемого метода поставки настроек(ansible, puppet, dockerfile, AWS AMI, ...) — при обновлении проще скопировать старый файл, чем в новом вручную прописывать те же настройки. Даже если переписывать файл с нуля — кто-то по привычке поставит # для комментария, и всё молча поломается.


  1. DjOnline
    16.09.2016 10:43
    +1

    Обратная совместимость? Нет, не знаем.


    1. vlreshet
      16.09.2016 11:21

      А какая обратная совместимость если изменилась мажорная версия?


      1. DjOnline
        16.09.2016 11:27
        +2

        Обратная совместимость не должна зависеть от версий совсем, особенно в enterprise языках, как сейчас позиционирует себя PHP.


        1. Fedcomp
          16.09.2016 12:34
          -1

          Мажорная версия имеет право сбрасывать костыли, иначе такой full of legacy никому будет не нужен в будующем.


          1. DjOnline
            16.09.2016 12:58
            +2

            Не имеет права. Иначе получается ужасная ситуация, когда есть тонны старого работающего кода, но обновлять версию нельзя из-за проблем совместимости, но и продолжать использовать старые версии тоже нельзя из-за прекращения поддержки и дыр в безопасности.


            1. edogs
              16.09.2016 13:18

              С такой логикой новые deprecated функции тоже не имеют право на существование, ведь из-за их наличия нельзя обновится, а старую версию нельзя использовать из-за дыр.

              Проблема возникает только в том случае, когда конфиг файл накатили от несовместимой версии. Ну так не накатывайте, перенести настройки или проверьте его на совместимость. Вот и всё решение.


            1. symbix
              16.09.2016 13:20

              О том, что # — deprecated, предупреждало в startup errors года 3-4.

              Вас послушать — так и register globals с magic quotes надо вечно тянуть было.

              >обновлять версию нельзя из-за проблем совместимости
              sed -i 's/^#/;/' php.ini
              Ужасная проблема совместимости. Исправить уйдут человекогоды.


  1. symbix
    16.09.2016 10:45
    +1

    Это ж каким ССЗБ надо быть, чтобы обновить мажорную версию прямо на продакшене без тестирования.


    1. selivanov_pavel
      16.09.2016 12:34
      +1

      Так в том и весь прикол, что при тестировании всё работает, только со значениями по-умолчанию. Если не используются загрузки больших файлов и другие явно ломающиеся вещи, то деградацию можно не заметить: странички открываются, все функции приложения работают, 500 не выпадает. А то, что оно начало отдавать X-Powered-By:, больше не органичивает доступные PHP функции и на ошибки отдаёт пользователю стектрейс — с первого взгляда не видно.


      1. symbix
        16.09.2016 13:14

        У вас тестирование сводится к «странички открываются»? Acceptance-тесты, CI — не?

        >больше не органичивает доступные PHP функции
        а это вообще зачем, кроме шаред-хостинга?


        1. edogs
          16.09.2016 13:21
          +2

          Удивительно видеть в одном сообщении претензию к отсутствию полноценного тестирования и удивление по поводу ограничивания функций.

          Вы наверное на сервере из под рута все время работаете? Исходя из логики «а зачем не из под рута, ведь доступ только у меня»:)

          Дыры могут быть в любом сайте, отключение некоторых функций пхп это банально безопаснее, т.к. по крайней мере Вы можете быть уверены, что даже если Ваш пхп сайт ломанут, то хотя бы в консоли не смогут чего-нибудь выполнить через пхп.


          1. symbix
            16.09.2016 22:15

            Достаточно нормально настроить ограничения средствами операционной системы. Это и понадежнее будет.


            1. edogs
              17.09.2016 01:50

              Сознательно отказаться от дополнительного слоя безопасности? Ради чего?
              Или Вы не в курсе что ОС тоже имеют уязвимости?
              Trust noone:)

              Вот, кстати, ничего так пример обхода ограничений https://habrahabr.ru/company/pentestit/blog/227497/


        1. selivanov_pavel
          16.09.2016 13:27
          +1

          У вас тестирование сводится к «странички открываются»? Acceptance-тесты, CI — не?

          Оно прошло тестирование, подробности — NDA. Разумеется, теперь мы добавили дополнительные проверки.


          а это вообще зачем, кроме шаред-хостинга?

          Немного уменьшаем поверхность атаки на случай уязвимостей в коде. Не факт что сильно поможет, но и не помешает


  1. youlose
    16.09.2016 13:02

    Вообще это похоже на проблему php-fpm, это же он стартует с неправильным конфигом?
    Лучше им напишите репорт.


    1. selivanov_pavel
      16.09.2016 14:02

      По заявкам телезрителей: https://bugs.php.net/bug.php?id=73099


  1. mxms
    16.09.2016 14:14
    -2

    Не «сервера», а «серверы» будет по-русски.


    1. selivanov_pavel
      16.09.2016 14:33
      +1

      https://ru.wiktionary.org/wiki/сервер:


      В разговорной речи встречается также вариант склонения по схеме 1c(1) (мн. ч. сервера?, серверо?в, сервера?м, сервера?ми, сервера?х).

      На мой вкус сервера звучит приятнее, но ваш вариант более академически привильный.


      1. mxms
        16.09.2016 16:34
        -5

        Во-первых, здесь не разговорная речь. Во-вторых, в разговорной речи, например, говорят «ихний» и «кушайте», что автоматически не делает эти слова часть> грамотного изъяснения на русском. И, наконец, в-третьих — вы, конечно, вольны делать что хотите, но окружающие будут судить о вашем образовании и интеллекте, в первую очередь, по степени владения языком.


        1. VolCh
          16.09.2016 20:56

          Здесь как раз разговорная речь, а не литературная.


        1. borNfree
          16.09.2016 21:38

          по степени владения языком


          надеюсь вы про PHP ;)