Изменение в PHP 7, ломающее при обновлении с пятой версии некоторые сервера на Ubuntu

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


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

Share post

Comments 27

    +10
    Если php.ini был скопирован из пятой версии
    При чём тут Ubuntu Xenial, если вы скопировали этот файл вручную?
    На убунте пхп 7 имеет отдельные папки для конфигов и она создаёт там новые конфиги при установке.
      0
      Именно тот случай, где сделали — то, чего нельзя было делать и изобрели к нему костыли. К тому же у xenial по умолчанию стоят ppa не от ondrej/php.
        0
        К тому же у xenial по умолчанию стоят ppa не от ondrej/php.

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

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

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

        +2
        Обратная совместимость? Нет, не знаем.
          0
          А какая обратная совместимость если изменилась мажорная версия?
            +2
            Обратная совместимость не должна зависеть от версий совсем, особенно в enterprise языках, как сейчас позиционирует себя PHP.
              –1
              Мажорная версия имеет право сбрасывать костыли, иначе такой full of legacy никому будет не нужен в будующем.
                +2
                Не имеет права. Иначе получается ужасная ситуация, когда есть тонны старого работающего кода, но обновлять версию нельзя из-за проблем совместимости, но и продолжать использовать старые версии тоже нельзя из-за прекращения поддержки и дыр в безопасности.
                  0
                  С такой логикой новые deprecated функции тоже не имеют право на существование, ведь из-за их наличия нельзя обновится, а старую версию нельзя использовать из-за дыр.

                  Проблема возникает только в том случае, когда конфиг файл накатили от несовместимой версии. Ну так не накатывайте, перенести настройки или проверьте его на совместимость. Вот и всё решение.
                    0
                    О том, что # — deprecated, предупреждало в startup errors года 3-4.

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

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

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

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

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

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

                  Дыры могут быть в любом сайте, отключение некоторых функций пхп это банально безопаснее, т.к. по крайней мере Вы можете быть уверены, что даже если Ваш пхп сайт ломанут, то хотя бы в консоли не смогут чего-нибудь выполнить через пхп.
                    0
                    Достаточно нормально настроить ограничения средствами операционной системы. Это и понадежнее будет.
                      0
                      Сознательно отказаться от дополнительного слоя безопасности? Ради чего?
                      Или Вы не в курсе что ОС тоже имеют уязвимости?
                      Trust noone:)

                      Вот, кстати, ничего так пример обхода ограничений https://habrahabr.ru/company/pentestit/blog/227497/
                        0
                        Отключение функций — это иллюзия безопасности, в том и дело.
                        Если совмещать, это другой вопрос.
                          0
                          Возможно Вам стоит почитать больше про отключение функций.
                          Отключение функций это повышение безопасности, а не иллюзия, т.к. доступ из консоли имеет больше возможностей и прав, чем доступ непосредственно их пхп.
                          А ограничение доступа это всегда хорошо, даже если не совмещать.
                          Да и пассаж про совмещать странный, для Вас не самоочевидно что подходы к ограничению надо совмещать?
                    +1
                    У вас тестирование сводится к «странички открываются»? Acceptance-тесты, CI — не?

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


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

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

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

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


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

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

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


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

                  Only users with full accounts can post comments. Log in, please.