Opt-In Software Blog

Software, dvelopment, and practical insights

Сборка PHP 8.2.35 для CentOS 7 в Docker

Читать на другом языке: English | Русский

CentOS 7 завершила жизненный цикл в июне 2024 года, но некоторые существующие серверы всё ещё должны работать на этой системе. В этой статье я расскажу, как собрал PHP 8.2.35 для CentOS 7.9 x86_64, скомпилировал несколько PECL-расширений и подготовил файлы для установки на сервер с Apache.

Идея заключается в том, чтобы собрать PHP в Docker-контейнере с инструментами, совместимыми с CentOS 7, а затем перенести результат на целевой сервер. Это позволяет не устанавливать все инструменты разработки непосредственно на рабочую машину.

Почему мне понадобился PHP 8.2.35

21 октября 2026 года команда PHP выпустила PHP 8.2.35, устраняющий две критические уязвимости удалённого выполнения кода: CVE-2026-109618 и CVE-2026-109619. Уязвимости затрагивали предыдущие версии ветки PHP 8.2 и могли позволить злоумышленнику выполнять код на сервере без аутентификации.

Уязвимости были связаны с обработкой памяти внутри самого PHP. Команда безопасности PHP особо отметила повышенный риск для конфигураций Apache с mod_php: специально сформированный HTTP-запрос мог запустить эксплуатацию уязвимости ещё до выполнения кода приложения.

Источники: официальное объявление о выпуске PHP 8.2.35 и архив объявлений PHP.

На моём сервере использовалась более старая версия PHP 8.2 с Apache mod_php. Поскольку стандартные пакеты PHP для устаревшей системы CentOS 7 не предоставляли нужную исправленную версию, я решил собрать PHP 8.2.35 из исходников в Docker и установить его отдельно в /opt/php-8.2.35.

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

Сама CentOS 7 больше не поддерживается, поэтому это решение следует рассматривать как способ обеспечить совместимость со старой системой, а не как долгосрочную замену обновлению операционной системы.

1. Подготовка окружения для сборки в Docker

В качестве основы я использовал образ manylinux2014_x86_64 и настроил в нём архивные репозитории CentOS 7.9. Полный Dockerfile доступен в этом GitHub Gist.

В Windows создадим рабочий каталог и сохраним в нём Dockerfile:

mkdir C:\php-build
cd C:\php-build

Соберём образ для архитектуры x86_64:

docker build --platform linux/amd64 -t php82-centos7-builder .

Запустим контейнер:

docker run -it --name php82-builder php82-centos7-builder

Dockerfile настраивает архивные репозитории CentOS 7.9 и EPEL 7, устанавливает зависимости для сборки и добавляет GCC из Developer Toolset 10 в окружение. Кроме того, он собирает re2c 1.0.3 из исходного кода.

Внутри контейнера можно проверить окружение следующими командами:

cat /etc/centos-release
gcc --version
rpm -q httpd httpd-devel
apxs -q LIBEXECDIR
apxs -q INCLUDEDIR

Пакет разработки Apache необходим для сборки PHP с помощью apxs, который создаёт модуль Apache.

2. Загрузка и настройка PHP

Скачайте исходный архив PHP 8.2.35 с официального сайта PHP.

Распакуйте архив и перейдите в каталог с исходным кодом. Далее предполагается, что исходники находятся в /usr/local/src/php-8.2.35.

cd /usr/local/src

curl -fL --retry 3 \
  https://www.php.net/distributions/php-8.2.35.tar.gz \
  -o php-8.2.35.tar.gz

tar -xzf php-8.2.35.tar.gz
cd php-8.2.35

Для сборки используется префикс /opt/php-8.2.35. Включим необходимые приложению расширения:

cd /usr/local/src/php-8.2.35

PKG_CONFIG_PATH=/usr/lib64/pkgconfig \
SQLITE_CFLAGS="-I/usr/include" \
SQLITE_LIBS="-L/usr/lib64 -lsqlite3" \
./configure \
  --prefix=/opt/php-8.2.35 \
  --with-apxs2=/usr/bin/apxs \
  --with-config-file-path=/opt/php-8.2.35/etc \
  --with-config-file-scan-dir=/opt/php-8.2.35/etc/conf.d \
  --enable-bcmath \
  --enable-calendar \
  --enable-exif \
  --enable-ftp \
  --enable-mbstring \
  --enable-pcntl \
  --enable-posix \
  --enable-shmop \
  --enable-sockets \
  --enable-soap \
  --enable-sysvmsg \
  --enable-sysvsem \
  --enable-sysvshm \
  --enable-opcache \
  --enable-gd \
  --with-bz2 \
  --with-curl \
  --with-gmp \
  --with-openssl \
  --with-readline \
  --with-zlib \
  --with-mysqli=mysqlnd \
  --with-pdo-mysql=mysqlnd \
  --with-pdo-sqlite \
  --with-sqlite3 \
  --with-jpeg \
  --with-freetype \
  --with-snmp \
  --with-xsl \
  --with-gettext \
  --with-sodium

Для совместимости с этой старой системой перед компиляцией я также применил исправление в ext/openssl/xp_ssl.c:

sed -i '/#include "php_openssl.h"/a #if OPENSSL_VERSION_NUMBER < 0x10100000L\n#define ASN1_STRING_get0_data ASN1_STRING_data\n#endif' ext/openssl/xp_ssl.c

Соберём и установим PHP:

make -j2
make install

Я не включал ZTS. Эта сборка предназначена для Apache с mpm_prefork и модулем PHP для Apache (mod_php).

3. Сборка PECL-расширений

Мне также понадобились расширения ds, mongodb и xmlrpc. Они собираются отдельно с помощью утилит phpize и php-config из новой установки PHP.

DS

cd /usr/local/src
curl -fLO https://pecl.php.net/get/ds-1.8.0.tgz
tar -xzf ds-1.8.0.tgz
cd ds-1.8.0

/opt/php-8.2.35/bin/phpize
./configure --with-php-config=/opt/php-8.2.35/bin/php-config
make -j2
make install

MongoDB

cd /usr/local/src
curl -fL https://pecl.php.net/get/mongodb -o mongodb.tgz
tar -xzf mongodb.tgz
cd mongodb-*

/opt/php-8.2.35/bin/phpize
./configure \
  --with-php-config=/opt/php-8.2.35/bin/php-config \
  --enable-mongodb
make -j2
make install

XML-RPC

cd /usr/local/src
curl -fL https://pecl.php.net/get/xmlrpc -o xmlrpc.tgz
tar -xzf xmlrpc.tgz
cd /usr/local/src/xmlrpc-*

/opt/php-8.2.35/bin/phpize
./configure --with-php-config=/opt/php-8.2.35/bin/php-config
make -j2
make install

Команды для MongoDB и XML-RPC загружают текущие версии из PECL, а не версии с фиксированными номерами. Если нужна воспроизводимая сборка, выберите и зафиксируйте конкретные версии расширений.

4. Настройка расширений PHP

Создадим каталог конфигурации, скопируем шаблон php.ini-production и включим расширения:

mkdir -p /opt/php-8.2.35/etc/conf.d

cp /usr/local/src/php-8.2.35/php.ini-production \
   /opt/php-8.2.35/etc/php.ini

cat > /opt/php-8.2.35/etc/conf.d/20-extensions.ini <<'EOF'
extension=ds.so
extension=mongodb.so
extension=xmlrpc.so
zend_extension=opcache.so
EOF

Проверим конфигурацию и загруженные модули:

/opt/php-8.2.35/bin/php --ini
/opt/php-8.2.35/bin/php -v
/opt/php-8.2.35/bin/php -m

Каталог дополнительных конфигураций задаётся параметром --with-config-file-scan-dir. Каталог с собранными динамическими расширениями можно узнать командой:

/opt/php-8.2.35/bin/php-config --extension-dir

5. Формирование бандла для установки

Установка PHP в контейнере не создаёт каталог php-8.2.35-bundle автоматически. Его нужно создать самостоятельно и явно скопировать в него необходимые файлы.

В нашем контейнере используются следующие пути:

  • Установка PHP: /opt/php-8.2.35
  • Модуль Apache: /usr/lib64/httpd/modules/libphp.so
  • Каталог модулей Apache, определённый через apxs: /usr/lib64/httpd/modules

Создадим структуру бандла:

mkdir -p /tmp/php-8.2.35-bundle/opt
mkdir -p /tmp/php-8.2.35-bundle/usr/lib64/httpd/modules
mkdir -p /tmp/php-8.2.35-bundle/etc/httpd/conf.d

Скопируем установленный PHP и модуль Apache:

cp -a /opt/php-8.2.35 \
  /tmp/php-8.2.35-bundle/opt/

cp -a /usr/lib64/httpd/modules/libphp.so \
  /tmp/php-8.2.35-bundle/usr/lib64/httpd/modules/

Создадим конфигурацию обработчика PHP для Apache:

cat > /tmp/php-8.2.35-bundle/etc/httpd/conf.d/php.conf <<'EOF'
<IfModule php_module>
    <FilesMatch \.php$>
        SetHandler application/x-httpd-php
    </FilesMatch>
</IfModule>
EOF

Этот файл настраивает обработчик PHP, но сам по себе не загружает модуль. На целевом сервере должна быть директива LoadModule, указывающая на скопированный модуль. Если используется отдельная конфигурация, например /etc/httpd/conf.modules.d/20-php.conf, её также нужно обновить при установке. Нельзя одновременно загружать старый и новый модули PHP.

Теперь структура бандла выглядит так:

php-8.2.35-bundle/
├── opt/
│   └── php-8.2.35/
├── usr/
│   └── lib64/
│       └── httpd/
│           └── modules/
│               └── libphp.so
└── etc/
    └── httpd/
        └── conf.d/
            └── php.conf

Создадим архив из каталога /tmp, явно указав имя бандла:

tar -czf /tmp/php-8.2.35-centos7-x86_64.tar.gz \
  -C /tmp php-8.2.35-bundle

Проверим, что архив создан и содержит нужные файлы:

ls -lh /tmp/php-8.2.35-centos7-x86_64.tar.gz

tar -tzf /tmp/php-8.2.35-centos7-x86_64.tar.gz | head -40

В моём случае получился архив размером около 80 МБ.

6. Проверка сборки перед установкой

Проверим PHP и зависимости Apache-модуля:

/opt/php-8.2.35/bin/php -v
/opt/php-8.2.35/bin/php -m

ldd /usr/lib64/httpd/modules/libphp.so | grep 'not found'

Если последняя команда ничего не выводит, ldd не обнаружил отсутствующих зависимостей в контейнере сборки. Однако это не гарантирует, что все зависимости есть на целевом сервере: там их нужно проверить отдельно.

7. Копирование архива из Docker

Откройте PowerShell на компьютере с Windows. Если контейнер называется иначе, замените php82-builder его фактическим именем или идентификатором.

docker cp php82-builder:/tmp/php-8.2.35-centos7-x86_64.tar.gz `
  "$env:USERPROFILE\Downloads\php-8.2.35-centos7-x86_64.tar.gz"

Теперь архив можно перенести на сервер CentOS обычным для вас способом.

8. Установка на сервер CentOS

На целевом сервере сначала распакуем архив во временный каталог:

mkdir -p /tmp/php-deploy
tar -xzf /path/to/php-8.2.35-centos7-x86_64.tar.gz \
  -C /tmp/php-deploy

Скопируем файлы в нужные места:

cp -a /tmp/php-deploy/php-8.2.35-bundle/opt/php-8.2.35 \
  /opt/

cp -a /tmp/php-deploy/php-8.2.35-bundle/usr/lib64/httpd/modules/libphp.so \
  /usr/lib64/httpd/modules/

cp -a /tmp/php-deploy/php-8.2.35-bundle/etc/httpd/conf.d/php.conf \
  /etc/httpd/conf.d/

Убедимся, что Apache загружает новый модуль. Например, файл /etc/httpd/conf.modules.d/20-php.conf должен содержать:

LoadModule php_module /usr/lib64/httpd/modules/libphp.so

Если в существующей конфигурации есть дополнительные настройки, например DirectoryIndex, обработка .phar или параметры сессий, сохраните их. Перед изменениями сделайте резервную копию текущей конфигурации Apache.

Проверим, что Apache использует mpm_prefork и не загружает другой модуль PHP:

httpd -M | grep -E 'mpm_|php'

Проверим зависимости модуля на целевом сервере:

ldd /usr/lib64/httpd/modules/libphp.so | grep 'not found'

Если есть отсутствующие библиотеки, сначала установите необходимые зависимости.

9. Контексты SELinux

Если PHP установлен в /opt, для корректной работы SELinux могут понадобиться постоянные правила контекстов для каталога PHP, конфигурационных файлов и модуля Apache.

На целевом сервере для этой конфигурации используются следующие правила:

semanage fcontext -a -t usr_t '/opt/php-8\.2\.35(/.*)?'
semanage fcontext -a -t httpd_config_t '/opt/php-8\.2\.35/etc(/.*)?'
semanage fcontext -a -t httpd_modules_t '/usr/lib64/httpd/modules/libphp\.so'

restorecon -Rv /opt/php-8.2.35
restorecon -v /usr/lib64/httpd/modules/libphp.so

Если правило уже существует, сначала проверьте его, а не добавляйте дубликат. Результирующие метки можно проверить с помощью ls -Z и matchpathcon -V.

10. Проверка Apache и PHP

Перед перезапуском Apache проверим конфигурацию:

httpd -t

Если ошибок нет, перезапустим Apache и проверим статус:

systemctl restart httpd
systemctl status httpd

Проверим PHP CLI:

/opt/php-8.2.35/bin/php -v
/opt/php-8.2.35/bin/php -m

В завершение проверьте PHP через веб-сервер с помощью временного тестового скрипта. Убедитесь, что версия — 8.2.35, SAPI — apache2handler, а используемый файл конфигурации — /opt/php-8.2.35/etc/php.ini. После проверки удалите тестовый скрипт.

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

Заключение

Сборка PHP в отдельном контейнере, совместимом с CentOS 7, позволяет не устанавливать компилятор и пакеты разработки на рабочий сервер. Главное — явно собрать бандл из установленного дерева PHP, модуля Apache и конфигурации обработчика, а затем проверить зависимости и метки SELinux на целевой системе.

CentOS 7 больше не поддерживается, поэтому этот подход стоит рассматривать как способ обслуживания существующего сервера на переходный период, пока готовится обновление до поддерживаемой операционной системы.

Search