- 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"] |
--- 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 { |
イメージを作成
ファイル構成は以下の通り
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 にアクセス
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 をつけているにもかかわらず上記エラーが発生
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 環境を構築する – Qiita、php5.2.14 と apache2.4.3 – rougeref’s diaryより、Apache 2.4 では unix_config が ap_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