Это явно не заслуживает отдельной статьи на Хабре, но ошибка может коснуться большого количества людей, поэтому я всё-таки решил написать.
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)
DjOnline
16.09.2016 10:43+1Обратная совместимость? Нет, не знаем.
vlreshet
16.09.2016 11:21А какая обратная совместимость если изменилась мажорная версия?
DjOnline
16.09.2016 11:27+2Обратная совместимость не должна зависеть от версий совсем, особенно в enterprise языках, как сейчас позиционирует себя PHP.
Fedcomp
16.09.2016 12:34-1Мажорная версия имеет право сбрасывать костыли, иначе такой full of legacy никому будет не нужен в будующем.
DjOnline
16.09.2016 12:58+2Не имеет права. Иначе получается ужасная ситуация, когда есть тонны старого работающего кода, но обновлять версию нельзя из-за проблем совместимости, но и продолжать использовать старые версии тоже нельзя из-за прекращения поддержки и дыр в безопасности.
edogs
16.09.2016 13:18С такой логикой новые deprecated функции тоже не имеют право на существование, ведь из-за их наличия нельзя обновится, а старую версию нельзя использовать из-за дыр.
Проблема возникает только в том случае, когда конфиг файл накатили от несовместимой версии. Ну так не накатывайте, перенести настройки или проверьте его на совместимость. Вот и всё решение.
symbix
16.09.2016 13:20О том, что # — deprecated, предупреждало в startup errors года 3-4.
Вас послушать — так и register globals с magic quotes надо вечно тянуть было.
>обновлять версию нельзя из-за проблем совместимости
sed -i 's/^#/;/' php.ini
Ужасная проблема совместимости. Исправить уйдут человекогоды.
symbix
16.09.2016 10:45+1Это ж каким ССЗБ надо быть, чтобы обновить мажорную версию прямо на продакшене без тестирования.
selivanov_pavel
16.09.2016 12:34+1Так в том и весь прикол, что при тестировании всё работает, только со значениями по-умолчанию. Если не используются загрузки больших файлов и другие явно ломающиеся вещи, то деградацию можно не заметить: странички открываются, все функции приложения работают, 500 не выпадает. А то, что оно начало отдавать
X-Powered-By:
, больше не органичивает доступные PHP функции и на ошибки отдаёт пользователю стектрейс — с первого взгляда не видно.symbix
16.09.2016 13:14У вас тестирование сводится к «странички открываются»? Acceptance-тесты, CI — не?
>больше не органичивает доступные PHP функции
а это вообще зачем, кроме шаред-хостинга?edogs
16.09.2016 13:21+2Удивительно видеть в одном сообщении претензию к отсутствию полноценного тестирования и удивление по поводу ограничивания функций.
Вы наверное на сервере из под рута все время работаете? Исходя из логики «а зачем не из под рута, ведь доступ только у меня»:)
Дыры могут быть в любом сайте, отключение некоторых функций пхп это банально безопаснее, т.к. по крайней мере Вы можете быть уверены, что даже если Ваш пхп сайт ломанут, то хотя бы в консоли не смогут чего-нибудь выполнить через пхп.symbix
16.09.2016 22:15Достаточно нормально настроить ограничения средствами операционной системы. Это и понадежнее будет.
edogs
17.09.2016 01:50Сознательно отказаться от дополнительного слоя безопасности? Ради чего?
Или Вы не в курсе что ОС тоже имеют уязвимости?
Trust noone:)
Вот, кстати, ничего так пример обхода ограничений https://habrahabr.ru/company/pentestit/blog/227497/
selivanov_pavel
16.09.2016 13:27+1У вас тестирование сводится к «странички открываются»? Acceptance-тесты, CI — не?
Оно прошло тестирование, подробности — NDA. Разумеется, теперь мы добавили дополнительные проверки.
а это вообще зачем, кроме шаред-хостинга?
Немного уменьшаем поверхность атаки на случай уязвимостей в коде. Не факт что сильно поможет, но и не помешает
youlose
16.09.2016 13:02Вообще это похоже на проблему php-fpm, это же он стартует с неправильным конфигом?
Лучше им напишите репорт.
mxms
16.09.2016 14:14-2Не «сервера», а «серверы» будет по-русски.
selivanov_pavel
16.09.2016 14:33+1https://ru.wiktionary.org/wiki/сервер:
В разговорной речи встречается также вариант склонения по схеме 1c(1) (мн. ч. сервера?, серверо?в, сервера?м, сервера?ми, сервера?х).
На мой вкус сервера звучит приятнее, но ваш вариант более академически привильный.
mxms
16.09.2016 16:34-5Во-первых, здесь не разговорная речь. Во-вторых, в разговорной речи, например, говорят «ихний» и «кушайте», что автоматически не делает эти слова часть> грамотного изъяснения на русском. И, наконец, в-третьих — вы, конечно, вольны делать что хотите, но окружающие будут судить о вашем образовании и интеллекте, в первую очередь, по степени владения языком.
youlose
Если php.ini был скопирован из пятой версии
При чём тут Ubuntu Xenial, если вы скопировали этот файл вручную?
На убунте пхп 7 имеет отдельные папки для конфигов и она создаёт там новые конфиги при установке.
imgen
Именно тот случай, где сделали — то, чего нельзя было делать и изобрели к нему костыли. К тому же у xenial по умолчанию стоят ppa не от ondrej/php.
selivanov_pavel
Проблема воспроизводится и в официальных пакетых от убунты, и в пакетах из ondrej/php.
selivanov_pavel
У нас этот файл раскладывается ролью ansible, и при переделывании роли с php5 на php7 я его просто скопировал и проверил по документации, что все используемые директивы работают так же. Вне зависимости от используемого метода поставки настроек(ansible, puppet, dockerfile, AWS AMI, ...) — при обновлении проще скопировать старый файл, чем в новом вручную прописывать те же настройки. Даже если переписывать файл с нуля — кто-то по привычке поставит
#
для комментария, и всё молча поломается.