Apache 2.4.54とPHP 5.2.17のDockerイメージを作る

  • Apache 2.4.54 と PHP 5.2.17 の Docker イメージがオフィシャルでなかったのでソースをビルドする形でイメージを作成する
  • PHP 5.2 は古いため、ビルドの際の依存パッケージのバージョンも古いほうがいいと思ったので、ベースの OS は、Ubuntu14.04 を使うことにした
  • マルチステージビルドでサイズを減らした
  • PHP はデフォルトに加え以下のモジュールを組み込む
    • GD(jpeg,png,freetype2)
    • mbstring
    • MySQL
    • PDO MySQL
    • MySQLi
    • zlib
    • OpenSSL
    • cURL
    • hash
    • mhash
    • mcrypt
    • zip

作成した Dockerfile 一式(Dockerfile と PHP のソースコードに適用するパッチが3つ)

--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -328,10 +328,12 @@ static inline int php_openssl_setup_cryp
sslsock->is_client = 1;
method = SSLv23_client_method();
break;
+#ifndef OPENSSL_NO_SSL2
case STREAM_CRYPTO_METHOD_SSLv2_CLIENT:
sslsock->is_client = 1;
method = SSLv2_client_method();
break;
+#endif
case STREAM_CRYPTO_METHOD_SSLv3_CLIENT:
sslsock->is_client = 1;
method = SSLv3_client_method();
@@ -348,10 +350,12 @@ static inline int php_openssl_setup_cryp
sslsock->is_client = 0;
method = SSLv3_server_method();
break;
+#ifndef OPENSSL_NO_SSL2
case STREAM_CRYPTO_METHOD_SSLv2_SERVER:
sslsock->is_client = 0;
method = SSLv2_server_method();
break;
+#endif
case STREAM_CRYPTO_METHOD_TLS_SERVER:
sslsock->is_client = 0;
method = TLSv1_server_method();
@@ -629,9 +633,11 @@ static inline int php_openssl_tcp_sockop
case STREAM_CRYPTO_METHOD_SSLv23_CLIENT:
sock->method = STREAM_CRYPTO_METHOD_SSLv23_SERVER;
break;
+#ifndef OPENSSL_NO_SSL2
case STREAM_CRYPTO_METHOD_SSLv2_CLIENT:
sock->method = STREAM_CRYPTO_METHOD_SSLv2_SERVER;
break;
+#endif
case STREAM_CRYPTO_METHOD_SSLv3_CLIENT:
sock->method = STREAM_CRYPTO_METHOD_SSLv3_SERVER;
break;
@@ -911,9 +917,11 @@ php_stream *php_openssl_ssl_socket_facto
if (strncmp(proto, "ssl", protolen) == 0) {
sslsock->enable_on_connect = 1;
sslsock->method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
+#ifndef OPENSSL_NO_SSL2
} else if (strncmp(proto, "sslv2", protolen) == 0) {
sslsock->enable_on_connect = 1;
sslsock->method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT;
+#endif
} else if (strncmp(proto, "sslv3", protolen) == 0) {
sslsock->enable_on_connect = 1;
sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
# ビルドステージ
FROM ubuntu:14.04 as build
# ビルドに必要なもの
ENV BUILD_DEPENDENCIES curl make patch
RUN apt update && apt install -y $BUILD_DEPENDENCIES && rm -r /var/lib/apt/lists/*
ENV SOURCE_DIR /usr/local/src
# Apacheビルド
ENV APACHE_BUILD_DEPENDENCIES libapr1-dev libaprutil1-dev
ENV APACHE_SOURCE_DIR $SOURCE_DIR/httpd
RUN set -eux \
# 依存パッケージインストール
&& apt update && apt install -y $APACHE_BUILD_DEPENDENCIES \
# ソースコードダウンロード・展開
&& cd $SOURCE_DIR \
&& curl -SL https://archive.apache.org/dist/httpd/httpd-2.4.54.tar.gz -o httpd.tar.gz \
&& mkdir -p $APACHE_SOURCE_DIR \
&& tar -xf httpd.tar.gz -C $APACHE_SOURCE_DIR --strip-components=1 \
# configure, make
&& cd httpd \
&& ./configure --enable-so \
&& make -j"$(nproc)" \
# インストール
&& make install \
# ビルドファイル、依存パッケージ削除
&& rm -r $SOURCE_DIR/httpd.tar.gz $APACHE_SOURCE_DIR \
&& apt remove -y $APACHE_BUILD_DEPENDENCIES \
&& apt-get autoremove -y && rm -r /var/lib/apt/lists/*
# PHP設定ファイルディレクトリを作成
ENV PHP_BUILD_DEPENDENCIES libapr1-dev libaprutil1-dev \
libxml2-dev libcurl4-openssl-dev libjpeg-dev \
libpng12-dev libfreetype6-dev libt1-dev libmcrypt-dev libmhash-dev libmysqlclient-dev libltdl7-dev
ENV PHP_SOURCE_DIR $SOURCE_DIR/php
ENV PHP_INI_DIR /usr/local/etc/php
RUN mkdir -p $PHP_INI_DIR/conf.d
# パッチをコピー
COPY patch/*.patch $PHP_SOURCE_DIR/
# PHPビルド
RUN set -eux \
# 依存パッケージインストール
&& apt update && apt install -y $PHP_BUILD_DEPENDENCIES \
# FreeType2インクルードファイルパス調整
&& mkdir -pv /usr/include/freetype2/freetype \
&& ln -sf /usr/include/freetype2/freetype.h /usr/include/freetype2/freetype/freetype.h \
# ソースコードダウンロード・展開
&& cd $SOURCE_DIR \
&& curl -SL "http://museum.php.net/php5/php-5.2.17.tar.bz2" -o php.tar.bz2 \
&& mkdir -p $PHP_SOURCE_DIR \
&& tar -xf php.tar.bz2 -C $PHP_SOURCE_DIR --strip-components=1 \
&& cd $PHP_SOURCE_DIR \
# パッチ
&& patch -p0 -b < $PHP_SOURCE_DIR/xml.patch \
&& patch -p1 -b < $PHP_SOURCE_DIR/debian_patches_disable_SSLv2_for_openssl_1_0_0.patch \
&& patch -l -p0 -b < $PHP_SOURCE_DIR/libphp5.so.patch \
# configure, make
&& ./configure \
--with-config-file-path=$PHP_INI_DIR \
--with-config-file-scan-dir=$PHP_INI_DIR/conf.d \
--with-libdir=lib/x86_64-linux-gnu \
--with-apxs2=/usr/local/apache2/bin/apxs \
--with-gd \
--with-png-dir=/usr/lib \
--with-jpeg-dir=/usr/lib \
--with-freetype-dir \
--enable-mbstring \
--with-mysql \
--with-mysqli \
--with-pdo-mysql \
--with-zlib \
--with-openssl \
--with-curl \
--with-mhash \
--with-mcrypt \
--enable-zip \
&& make -j"$(nproc)" \
# インストール
&& make install \
# 設定ファイルコピー
&& cp /usr/local/src/php/php.ini-recommended $PHP_INI_DIR/php.ini-recommended \
# # ビルドファイル、依存パッケージ削除
&& rm -r $SOURCE_DIR//php.tar.bz2 $PHP_SOURCE_DIR \
&& apt remove -y $PHP_BUILD_DEPENDENCIES \
&& apt-get autoremove -y && rm -r /var/lib/apt/lists/*
RUN apt remove -y $BUILD_DEPENDENCIES && apt-get autoremove -y && rm -r /var/lib/apt/lists/*
# ランタイムステージ
FROM ubuntu:14.04 as runtime
# 依存パッケージのインストール
ENV RUNTIME_DEPENDENCIES libapr1 libaprutil1 libcurl3 libxml2 libjpeg8 libfreetype6 \
libt1-5 libmcrypt4 libmhash2 libmysqlclient18
RUN apt update \
&& apt install -y $RUNTIME_DEPENDENCIES \
&& rm -r /var/lib/apt/lists/*
# 生成物コピー
COPY --from=build /usr/local /usr/local
# Apache設定
RUN set -eux \
&& cd / \
&& mkdir -p /var/www/html \
&& sed -i -r " \
s/(DirectoryIndex index[.])html/\1php index\.html/; \
s#/usr/local/apache2/htdocs#/var/www/html#g; \
s#^(\s*CustomLog)\s+\S+#\1 /proc/self/fd/1#g; \
s#^(\s*ErrorLog)\s+\S+#\1 /proc/self/fd/2#g; \
s/#LoadModule rewrite_module/LoadModule rewrite_module/g; \
/<Directory \"\/var\/www\/html\">/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/; \
$ a<FilesMatch \\.php$>\n\tSetHandler application/x-httpd-php\n</FilesMatch> \
" /usr/local/apache2/conf/httpd.conf \
&& echo "<html><head></head><body><?php echo '<h1>Hello, World!</h1>'; ?></body></html>" > /var/www/html/index.php
# PHP設定
ENV PHP_INI_DIR /usr/local/etc/php
RUN set -eux \
&& sed '/\;error_log = syslog/a error_log=/proc/1/fd/2' $PHP_INI_DIR/php.ini-recommended > $PHP_INI_DIR/php.ini
ENV PATH $PATH:/usr/local/apache2/bin
ENV PATH $PATH:/usr/local/bin/
WORKDIR /var/www/html
VOLUME /var/www/html
EXPOSE 80
CMD ["httpd", "-DFOREGROUND"]
view raw Dockerfile hosted with ❤ by GitHub
--- sapi/apache2handler/php_functions.c 2023-01-19 14:24:50.358748972 +0000
+++ sapi/apache2handler/php_functions.c 2023-01-19 14:24:34.889896546 +0000
@@ -383,7 +383,7 @@
char *p;
server_rec *serv = ((php_struct *) SG(server_context))->r->server;
#if !defined(WIN32) && !defined(WINNT) && !defined(NETWARE)
- AP_DECLARE_DATA extern unixd_config_rec unixd_config;
+ AP_DECLARE_DATA extern unixd_config_rec ap_unixd_config;
#endif
for (n = 0; ap_loaded_modules[n]; ++n) {
@@ -414,7 +414,7 @@
php_info_print_table_row(2, "Hostname:Port", tmp);
#if !defined(WIN32) && !defined(WINNT) && !defined(NETWARE)
- snprintf(tmp, sizeof(tmp), "%s(%d)/%d", unixd_config.user_name, unixd_config.user_id, unixd_config.group_id);
+ snprintf(tmp, sizeof(tmp), "%s(%d)/%d", ap_unixd_config.user_name, ap_unixd_config.user_id, ap_unixd_config.group_id);
php_info_print_table_row(2, "User/Group", tmp);
#endif
--- ext/dom/node.c 2012-08-06 17:49:48.826716692 +0800
+++ ext/dom/node.c 2012-08-06 17:52:47.633484660 +0800
@@ -1895,9 +1895,17 @@ static void dom_canonicalization(INTERNA
RETVAL_FALSE;
} else {
if (mode == 0) {
+#ifdef LIBXML2_NEW_BUFFER
+ ret = xmlOutputBufferGetSize(buf);
+#else
ret = buf->buffer->use;
+#endif
if (ret > 0) {
+#ifdef LIBXML2_NEW_BUFFER
+ RETVAL_STRINGL((char *) xmlOutputBufferGetContent(buf), ret, 1);
+#else
RETVAL_STRINGL((char *) buf->buffer->content, ret, 1);
+#endif
} else {
RETVAL_EMPTY_STRING();
}
--- ext/dom/documenttype.c 2012-08-06 18:02:16.019640870 +0800
+++ ext/dom/documenttype.c 2012-08-06 18:06:16.612228905 +0800
@@ -205,7 +205,13 @@ int dom_documenttype_internal_subset_rea
if (buff != NULL) {
xmlNodeDumpOutput (buff, NULL, (xmlNodePtr) intsubset, 0, 0, NULL);
xmlOutputBufferFlush(buff);
+
+#ifdef LIBXML2_NEW_BUFFER
+ ZVAL_STRINGL(*retval, xmlOutputBufferGetContent(buff),
+ xmlOutputBufferGetSize(buff), 1);
+#else
ZVAL_STRINGL(*retval, buff->buffer->content, buff->buffer->use, 1);
+#endif
(void)xmlOutputBufferClose(buff);
return SUCCESS;
}
--- ext/simplexml/simplexml.c 2012-08-06 18:10:44.621017026 +0800
+++ ext/simplexml/simplexml.c 2012-08-06 18:12:48.016270419 +0800
@@ -1417,7 +1417,12 @@ SXE_METHOD(asXML)
xmlNodeDumpOutput(outbuf, (xmlDocPtr) sxe->document->ptr, node, 0, 0, ((xmlDocPtr) sxe->document->ptr)->encoding);
xmlOutputBufferFlush(outbuf);
+#ifdef LIBXML2_NEW_BUFFER
+ RETVAL_STRINGL((char *)xmlOutputBufferGetContent(outbuf),
+ xmlOutputBufferGetSize(outbuf), 1);
+#else
RETVAL_STRINGL((char *)outbuf->buffer->content, outbuf->buffer->use, 1);
+#endif
xmlOutputBufferClose(outbuf);
}
} else {
view raw xml.patch hosted with ❤ by GitHub

イメージを作成

ファイル構成は以下の通り

Dockerfile
patch/
      debian_patches_disable_SSLv2_for_openssl_1_0_0.patch
      libphp5.so.patch
      xml.patch

ビルド

$ docker build -t php:5.2.17-apache2.4.54 .

コンテナを実行

このイメージでは、HTTP ポートは 80 で公開

ドキュメントルートは /var/www/html に設定している

htdocs ディレクトリを作成、その下に index.php を作成して

<?php
phpinfo();

としておく

$ docker run --rm -v $(pwd)/htdocs:/var/www/html -p 80:80 php:5.2.17-apache2.4.54

http://localhost にアクセス

phpinfo

Docker Compose を使用する場合の compose.yaml サンプル

services:
  php:
    build:
      dockerfile: Dockerfile
    volumes:
      - ./htdocs:/var/www/html
    ports:
      - 80:80

トラブルシュート

イメージを作成するまでのトラブルシュート

configure のエラー

configure: error: libjpeg.(a|so) not found.

libjpeg.so の位置を確認すると

# find /usr/lib -name "libjpeg.a"
/usr/lib/x86_64-linux-gnu/libjpeg.a

phpbrew/README.ja.md at master · phpbrew/phpbrewより、

–with-libdir で参照先を lib/x86_64-linux-gnu にセットしたうえで、–with-jpeg-dir,–with-png-dir/usr/lib にセットする

# ./configure \
 (省略)
 --with-libdir=lib/x86_64-linux-gnu \
 --with-gd \
 --with-png-dir=/usr/lib \
 --with-jpeg-dir=/usr/lib

configure: error: freetype.h not found.

libfreetype6-dev をインストールののち、configure に –with-freetype-dir をつけているにもかかわらず上記エラーが発生

Configure php 5.3 fail with error : freetype.h not found (but libfreetype6-dev is installed) – Stack Overflowより、

freetype.h の位置を調整する

freetype.h はビルドの際に必要だが、実行時には PHP のビルド成果物と libfreetype6 があれば問題ない

# mkdir /usr/include/freetype2/freetype
# ln -s /usr/include/freetype2/freetype.h /usr/include/freetype2/freetype/freetype.h

make のエラー

ext/dom/node.c:1953:21: error: dereferencing pointer to incomplete type

/usr/local/src/php/ext/dom/node.c: In function 'dom_canonicalization':
/usr/local/src/php/ext/dom/node.c:1953:21: error: dereferencing pointer to incomplete type
    ret = buf->buffer->use;
                     ^
In file included from /usr/local/src/php/main/php.h:38:0,
                 from /usr/local/src/php/ext/dom/node.c:26:
/usr/local/src/php/ext/dom/node.c:1955:40: error: dereferencing pointer to incomplete type
     RETVAL_STRINGL((char *) buf->buffer->content, ret, 1);
                                        ^
/usr/local/src/php/Zend/zend_API.h:472:14: note: in definition of macro 'ZVAL_STRINGL'
   char *__s=(s); int __l=l;  \
              ^
/usr/local/src/php/ext/dom/node.c:1955:5: note: in expansion of macro 'RETVAL_STRINGL'
     RETVAL_STRINGL((char *) buf->buffer->content, ret, 1);
     ^
make: *** [ext/dom/node.lo] Error 1

CentOS7.1 に PHP5.2.17 環境を構築する – Qiitaより、パッチが公開されているので適用する

# cd /usr/local/src/php
# curl -ksSL "https://mail.gnome.org/archives/xml/2012-August/txtF4xf2MZKEQ.txt" -o xml.patch
# patch -p0 -b < xml.patch
patching file ext/dom/node.c
Hunk #1 succeeded at 1950 (offset 55 lines).
patching file ext/dom/documenttype.c
Hunk #1 succeeded at 215 (offset 10 lines).
patching file ext/simplexml/simplexml.c
Hunk #1 succeeded at 1343 (offset -74 lines).

ext/openssl/xp_ssl.c:337: undefined reference to `SSLv2_client_method’

ext/openssl/.libs/xp_ssl.o: In function `php_openssl_setup_crypto':
/usr/local/src/php/ext/openssl/xp_ssl.c:337: undefined reference to `SSLv2_client_method'
/usr/local/src/php/ext/openssl/xp_ssl.c:357: undefined reference to `SSLv2_server_method'
collect2: error: ld returned 1 exit status
make: *** [sapi/cli/php] Error 1

PHP :: Bug #54736 :: Patchesより、パッチが公開されているので適用する

# cd /usr/local/src/php
# curl -sSL "https://bugs.php.net/patch-display.php?bug_id=54736&patch=debian_patches_disable_SSLv2_for_openssl_1_0_0.patch&revision=1305414559&download=1" -o debian_patches_disable_SSLv2_for_openssl_1_0_0.patch
# patch -p1 -b < debian_patches_disable_SSLv2_for_openssl_1_0_0.patch
patching file ext/openssl/xp_ssl.c
Hunk #1 succeeded at 332 (offset 4 lines).
Hunk #2 succeeded at 354 (offset 4 lines).
Hunk #3 succeeded at 583 (offset -50 lines).
Hunk #4 succeeded at 819 (offset -98 lines).

Apache 実行時の PHP5 モジュールエラー

Cannot load modules/libphp5.so into server: /usr/local/apache2/modules/libphp5.so: undefined symbol: unixd_config

# /usr/local/apache2/bin/httpd -DFOREGROUND
httpd: Syntax error on line 157 of /usr/local/apache2/conf/httpd.conf: Cannot load modules/libphp5.so into server: /usr/local/apache2/modules/libphp5.so: undefined symbol: unixd_config

CentOS7.1 に PHP5.2.17 環境を構築する – Qiitaphp5.2.14 と apache2.4.3 – rougeref’s diaryより、Apache 2.4 では unix_configap_unixd_config に変更された

ap_unixd_config に合わせるように sapi/apache2handler/php_functions.c 内を変更する。変更箇所は上記リンク参照

変更箇所はパッチ形式になっているので、パッチファイル名を libphp5.so.patch として作成・保存し、適用する

# patch -l -p0 -b < libphp5.so.patch
patching file sapi/apache2handler/php_functions.c

その他のエラー

buildconf: Your version of autoconf likely contains buggy cache code.

当初、php/Dockerfile at 0985a4d4ba7d16e273d14ca582562767b823cf08 · docker-library/phpをベースしていたころ、 ./buildconf --forceの実行時に発生したエラー

./buildconf --force
Forcing buildconf
buildconf: checking installation...
buildconf: autoconf version 2.69 (ok)
buildconf: Your version of autoconf likely contains buggy cache code.
           Running vcsclean for you.
           To avoid this, install autoconf-2.13.
Can't figure out your VCS, not cleaning.

编译 php 报 Can’t figure out your VCS, not cleaning – 夜空より、

autoconf2.13 をインストールする

apt-get install -y autoconf2.13

再度実行

./buildconf --force
Forcing buildconf
buildconf: checking installation...
buildconf: autoconf version 2.13 (ok)

patch コマンドの-l オプション

上記 libphp5.so.patch をサイトのコードをコピーして保存し、patch コマンドで適用しようとしたところ、内容は問題ないのに正常に適用できなかった。

# patch -p0 -b < libphp5.so.patch
patching file sapi/apache2handler/php_functions.c
Hunk #1 FAILED at 383.
Hunk #2 FAILED at 414.
2 out of 2 hunks FAILED -- saving rejects to file sapi/apache2handler/php_functions.c.rej

元のソースコードとパッチの差分をよく確認してみると、ソースコードはタブ、パッチファイルはスペースになっていた。

コードの内容は問題なかったので、-l オプションをつけて空白とタブの区別を無視したうえでパッチを適用するようにした

# patch -l -p0 -b < libphp5.so.patch
patching file sapi/apache2handler/php_functions.c

参考