php/Dockerfile-linux.template
Tianon Gravi dc710cdc49 Move GPG keys into the template
They don't change within a release very often, so it doesn't feel "correct" to embed them in the block of more dynamic information we embed in versions.json (and IMO we get slightly better syntax this way).
2022-01-27 11:23:31 -08:00

505 lines
16 KiB
Docker

{{
def version_id:
# https://www.php.net/phpversion
# $version_id = $major_version * 10000 + $minor_version * 100 + $release_version;
sub("[a-zA-Z].*$"; "")
| split(".")
| (
(.[0] // 0 | tonumber) * 10000
+ (.[1] // 0 | tonumber) * 100
+ (.[2] // 0 | tonumber)
)
;
def is_alpine:
env.from | startswith("alpine")
-}}
FROM {{ env.from }}
{{ if is_alpine then "" else ( -}}
# prevent Debian's PHP packages from being installed
# https://github.com/docker-library/php/pull/542
RUN set -eux; \
{ \
echo 'Package: php*'; \
echo 'Pin: release *'; \
echo 'Pin-Priority: -1'; \
} > /etc/apt/preferences.d/no-debian-php
{{ ) end -}}
# dependencies required for running "phpize"
{{ if is_alpine then ( -}}
# these get automatically installed and removed by "docker-php-ext-*" (unless they're already installed)
{{ ) else ( -}}
# (see persistent deps below)
{{ ) end -}}
ENV PHPIZE_DEPS \
autoconf \
dpkg-dev {{ if is_alpine then "dpkg " else "" end }}\
file \
g++ \
gcc \
libc-dev \
make \
{{ if is_alpine then "pkgconf" else "pkg-config" end }} \
re2c
# persistent / runtime deps
{{ if is_alpine then ( -}}
RUN apk add --no-cache \
ca-certificates \
curl \
tar \
xz \
# https://github.com/docker-library/php/issues/494
openssl
# ensure www-data user exists
RUN set -eux; \
{{ if env.alpineVer == "3.13" then ( -}}
addgroup -g 82 -S www-data; \
{{ ) else "" end -}}
adduser -u 82 -D -S -G www-data www-data
# 82 is the standard uid/gid for "www-data" in Alpine
# https://git.alpinelinux.org/aports/tree/main/apache2/apache2.pre-install?h=3.14-stable
# https://git.alpinelinux.org/aports/tree/main/lighttpd/lighttpd.pre-install?h=3.14-stable
# https://git.alpinelinux.org/aports/tree/main/nginx/nginx.pre-install?h=3.14-stable
{{ ) else ( -}}
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
$PHPIZE_DEPS \
ca-certificates \
curl \
xz-utils \
; \
rm -rf /var/lib/apt/lists/*
{{ ) end -}}
ENV PHP_INI_DIR /usr/local/etc/php
RUN set -eux; \
mkdir -p "$PHP_INI_DIR/conf.d"; \
# allow running as an arbitrary user (https://github.com/docker-library/php/issues/743)
[ ! -d /var/www/html ]; \
mkdir -p /var/www/html; \
chown www-data:www-data /var/www/html; \
chmod 777 /var/www/html
{{ if env.variant == "apache" then ( -}}
ENV APACHE_CONFDIR /etc/apache2
ENV APACHE_ENVVARS $APACHE_CONFDIR/envvars
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends apache2; \
rm -rf /var/lib/apt/lists/*; \
\
# generically convert lines like
# export APACHE_RUN_USER=www-data
# into
# : ${APACHE_RUN_USER:=www-data}
# export APACHE_RUN_USER
# so that they can be overridden at runtime ("-e APACHE_RUN_USER=...")
sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS"; \
\
# setup directories and permissions
. "$APACHE_ENVVARS"; \
for dir in \
"$APACHE_LOCK_DIR" \
"$APACHE_RUN_DIR" \
"$APACHE_LOG_DIR" \
; do \
rm -rvf "$dir"; \
mkdir -p "$dir"; \
chown "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$dir"; \
# allow running as an arbitrary user (https://github.com/docker-library/php/issues/743)
chmod 777 "$dir"; \
done; \
\
# delete the "index.html" that installing Apache drops in here
rm -rvf /var/www/html/*; \
\
# logs should go to stdout / stderr
ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log"; \
ln -sfT /dev/stdout "$APACHE_LOG_DIR/access.log"; \
ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log"; \
chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR"
# Apache + PHP requires preforking Apache for best results
RUN a2dismod mpm_event && a2enmod mpm_prefork
# PHP files should be handled by PHP, and should be preferred over any other file type
RUN { \
echo '<FilesMatch \.php$>'; \
echo '\tSetHandler application/x-httpd-php'; \
echo '</FilesMatch>'; \
echo; \
echo 'DirectoryIndex disabled'; \
echo 'DirectoryIndex index.php index.html'; \
echo; \
echo '<Directory /var/www/>'; \
echo '\tOptions -Indexes'; \
echo '\tAllowOverride All'; \
echo '</Directory>'; \
} | tee "$APACHE_CONFDIR/conf-available/docker-php.conf" \
&& a2enconf docker-php
{{ ) else "" end -}}
# Apply stack smash protection to functions using local buffers and alloca()
# Make PHP's main executable position-independent (improves ASLR security mechanism, and has no performance impact on x86_64)
# Enable optimization (-O2)
# Enable linker optimization (this sorts the hash buckets to improve cache locality, and is non-default)
# https://github.com/docker-library/php/issues/272
# -D_LARGEFILE_SOURCE and -D_FILE_OFFSET_BITS=64 (https://www.php.net/manual/en/intro.filesystem.php)
ENV PHP_CFLAGS="-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"
ENV PHP_CPPFLAGS="$PHP_CFLAGS"
ENV PHP_LDFLAGS="-Wl,-O1 -pie"
ENV GPG_KEYS {{
{
# https://www.php.net/gpg-keys.php
# https://www.php.net/downloads.php
"8.1": [
# https://wiki.php.net/todo/php81#release_managers
# https://www.php.net/gpg-keys.php#gpg-8.1
"5289 95BF EDFB A719 1D46 839E F9BA 0ADA 31CB D89E", # krakjoe
"39B6 4134 3D8C 104B 2B14 6DC3 F9C3 9DC0 B969 8544", # ramsey
"F1F6 9223 8FBC 1666 E5A5 CCD4 199F 9DFE F6FF BAFD" # patrickallaert
],
"8.0": [
# https://wiki.php.net/todo/php80#release_managers
# https://www.php.net/gpg-keys.php#gpg-8.0
"1729 F839 38DA 44E2 7BA0 F4D3 DBDB 3974 70D1 2172", # pollita
"BFDD D286 4282 4F81 18EF 7790 9B67 A5C1 2229 118F" # carusogabriel
],
"7.4": [
# https://wiki.php.net/todo/php74#release_managers
# https://www.php.net/gpg-keys.php#gpg-7.4
"4267 0A7F E4D0 441C 8E46 3234 9E4F DC07 4A4E F02D", # petk
"5A52 8807 81F7 5560 8BF8 15FC 910D EB46 F53E A312" # derick
],
"7.3": [
# https://wiki.php.net/todo/php73#release_managers
# https://www.php.net/gpg-keys.php#gpg-7.3
"CBAF 69F1 73A0 FEA4 B537 F470 D66C 9593 118B CCB6", # cmb
"F382 5282 6ACD 957E F380 D39F 2F79 56BC 5DA0 4B5D" # stas
],
}[env.version | rtrimstr("-rc")] // error("missing GPG keys for " + env.version)
| map(gsub(" "; ""))
| join(" ")
}}
ENV PHP_VERSION {{ .version }}
ENV PHP_URL="{{ .url }}" PHP_ASC_URL="{{ .ascUrl // "" }}"
ENV PHP_SHA256="{{ .sha256 // "" }}"
RUN set -eux; \
\
{{ if is_alpine then ( -}}
apk add --no-cache --virtual .fetch-deps gnupg; \
{{ ) else ( -}}
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends gnupg dirmngr; \
rm -rf /var/lib/apt/lists/*; \
{{ ) end -}}
\
mkdir -p /usr/src; \
cd /usr/src; \
\
curl -fsSL -o php.tar.xz "$PHP_URL"; \
\
if [ -n "$PHP_SHA256" ]; then \
echo "$PHP_SHA256 *php.tar.xz" | sha256sum -c -; \
fi; \
\
if [ -n "$PHP_ASC_URL" ]; then \
curl -fsSL -o php.tar.xz.asc "$PHP_ASC_URL"; \
export GNUPGHOME="$(mktemp -d)"; \
for key in $GPG_KEYS; do \
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
done; \
gpg --batch --verify php.tar.xz.asc php.tar.xz; \
gpgconf --kill all; \
rm -rf "$GNUPGHOME"; \
fi; \
\
{{ if is_alpine then ( -}}
apk del --no-network .fetch-deps
{{ ) else ( -}}
apt-mark auto '.*' > /dev/null; \
apt-mark manual $savedAptMark > /dev/null; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false
{{ ) end -}}
COPY docker-php-source /usr/local/bin/
RUN set -eux; \
{{ if is_alpine then ( -}}
apk add --no-cache --virtual .build-deps \
{{ ) else ( -}}
\
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
{{ ) end -}}
{{
[
[ if is_alpine then
# alpine packages
"$PHPIZE_DEPS",
"argon2-dev",
"coreutils",
"curl-dev",
"libsodium-dev",
"libxml2-dev",
"openssl-dev",
"readline-dev",
"sqlite-dev",
# https://github.com/docker-library/php/issues/888
if (.version | version_id) >= ("7.4" | version_id) then "linux-headers" else empty end,
# oniguruma is part of mbstring in php 7.4+
if (.version | version_id) >= ("7.4" | version_id) then "oniguruma-dev" else empty end
else
# debian packages
if env.variant == "apache" then "apache2-dev" else empty end,
"libargon2-dev",
"libcurl4-openssl-dev",
"libreadline-dev",
"libsodium-dev",
"libsqlite3-dev",
"libssl-dev",
"libxml2-dev",
"zlib1g-dev",
# oniguruma is part of mbstring in php 7.4+
if (.version | version_id) >= ("7.4" | version_id) then "libonig-dev" else empty end
end ] | sort[] | (
-}}
{{ . }} \
{{
)
] | add
-}}
; \
\
export \
CFLAGS="$PHP_CFLAGS" \
CPPFLAGS="$PHP_CPPFLAGS" \
LDFLAGS="$PHP_LDFLAGS" \
; \
docker-php-source extract; \
cd /usr/src/php; \
gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
{{ if is_alpine then "" else ( -}}
debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \
# https://bugs.php.net/bug.php?id=74125
if [ ! -d /usr/include/curl ]; then \
ln -sT "/usr/include/$debMultiarch/curl" /usr/local/include/curl; \
fi; \
{{ ) end -}}
./configure \
--build="$gnuArch" \
--with-config-file-path="$PHP_INI_DIR" \
--with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
\
# make sure invalid --configure-flags are fatal errors instead of just warnings
--enable-option-checking=fatal \
\
# https://github.com/docker-library/php/issues/439
--with-mhash \
\
# https://github.com/docker-library/php/issues/822
--with-pic \
\
# --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
--enable-ftp \
# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
--enable-mbstring \
# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)
--enable-mysqlnd \
# https://wiki.php.net/rfc/argon2_password_hash
--with-password-argon2 \
# https://wiki.php.net/rfc/libsodium
--with-sodium=shared \
# always build against system sqlite3 (https://github.com/php/php-src/commit/6083a387a81dbbd66d6316a3a12a63f06d5f7109)
--with-pdo-sqlite=/usr \
--with-sqlite3=/usr \
\
--with-curl \
--with-openssl \
--with-readline \
--with-zlib \
\
{{ if (.version | version_id) >= ("7.4" | version_id) then ( -}}
# in PHP 7.4+, the pecl/pear installers are officially deprecated (requiring an explicit "--with-pear")
--with-pear \
\
{{ ) else "" end -}}
# bundled pcre does not support JIT on s390x
# https://manpages.debian.org/bullseye/libpcre3-dev/pcrejit.3.en.html#AVAILABILITY_OF_JIT_SUPPORT
{{ if is_alpine then ( -}}
$(test "$gnuArch" = 's390x-linux-musl' && echo '--without-pcre-jit') \
{{ ) else ( -}}
$(test "$gnuArch" = 's390x-linux-gnu' && echo '--without-pcre-jit') \
--with-libdir="lib/$debMultiarch" \
{{ ) end -}}
{{ # https://github.com/docker-library/php/issues/280 -}}
{{ if env.variant == "cli" then "" else ( -}}
\
--disable-cgi \
{{ ) end -}}
{{ if (env.variant == "cli" or env.variant == "zts") and (is_alpine | not) then ( -}}
\
# https://github.com/docker-library/php/pull/939#issuecomment-730501748
--enable-embed \
{{ ) else "" end -}}
{{ if env.variant == "apache" then ( -}}
\
--with-apxs2 \
{{ ) elif env.variant == "fpm" then ( -}}
\
--enable-fpm \
--with-fpm-user=www-data \
--with-fpm-group=www-data \
{{ ) elif env.variant == "zts" then ( -}}
\
{{ if (.version | version_id) >= ("8" | version_id) then ( -}}
--enable-zts \
{{ ) else ( -}}
--enable-maintainer-zts \
{{ ) end -}}
{{ ) else "" end -}}
; \
make -j "$(nproc)"; \
find -type f -name '*.a' -delete; \
make install; \
find \
/usr/local \
-type f \
-perm '/0111' \
-exec sh -euxc ' \
strip --strip-all "$@" || : \
' -- '{}' + \
; \
make clean; \
\
# https://github.com/docker-library/php/issues/692 (copy default example "php.ini" files somewhere easily discoverable)
cp -v php.ini-* "$PHP_INI_DIR/"; \
\
cd /; \
docker-php-source delete; \
\
{{ if is_alpine then ( -}}
runDeps="$( \
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local \
| tr ',' '\n' \
| sort -u \
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
)"; \
apk add --no-cache $runDeps; \
\
apk del --no-network .build-deps; \
{{ ) else ( -}}
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \
find /usr/local -type f -executable -exec ldd '{}' ';' \
| awk '/=>/ { print $(NF-1) }' \
| sort -u \
| xargs -r dpkg-query --search \
| cut -d: -f1 \
| sort -u \
| xargs -r apt-mark manual \
; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
rm -rf /var/lib/apt/lists/*; \
{{ ) end -}}
\
# update pecl channel definitions https://github.com/docker-library/php/issues/443
pecl update-channels; \
rm -rf /tmp/pear ~/.pearrc; \
\
# smoke test
php --version
COPY docker-php-ext-* docker-php-entrypoint /usr/local/bin/
# sodium was built as a shared module (so that it can be replaced later if so desired), so let's enable it too (https://github.com/docker-library/php/issues/598)
RUN docker-php-ext-enable sodium
{{
# https://github.com/docker-library/php/issues/865
# https://bugs.php.net/bug.php?id=76324
# https://github.com/php/php-src/pull/3632
# https://github.com/php/php-src/commit/2d03197749696ac3f8effba6b7977b0d8729fef3
if (is_alpine | not) and (.version | version_id) < ("7.4" | version_id) then (
-}}
# temporary "freetype-config" workaround for https://github.com/docker-library/php/issues/865 (https://bugs.php.net/bug.php?id=76324)
RUN { echo '#!/bin/sh'; echo 'exec pkg-config "$@" freetype2'; } > /usr/local/bin/freetype-config && chmod +x /usr/local/bin/freetype-config
{{ ) else "" end -}}
ENTRYPOINT ["docker-php-entrypoint"]
{{ if env.variant == "apache" then ( -}}
# https://httpd.apache.org/docs/2.4/stopping.html#gracefulstop
STOPSIGNAL SIGWINCH
COPY apache2-foreground /usr/local/bin/
WORKDIR /var/www/html
EXPOSE 80
{{ ) elif env.variant == "fpm" then ( -}}
WORKDIR /var/www/html
RUN set -eux; \
cd /usr/local/etc; \
if [ -d php-fpm.d ]; then \
# for some reason, upstream's php-fpm.conf.default has "include=NONE/etc/php-fpm.d/*.conf"
sed 's!=NONE/!=!g' php-fpm.conf.default | tee php-fpm.conf > /dev/null; \
cp php-fpm.d/www.conf.default php-fpm.d/www.conf; \
else \
# PHP 5.x doesn't use "include=" by default, so we'll create our own simple config that mimics PHP 7+ for consistency
mkdir php-fpm.d; \
cp php-fpm.conf.default php-fpm.d/www.conf; \
{ \
echo '[global]'; \
echo 'include=etc/php-fpm.d/*.conf'; \
} | tee php-fpm.conf; \
fi; \
{ \
echo '[global]'; \
echo 'error_log = /proc/self/fd/2'; \
{{ if (.version | version_id) >= ("7.3" | version_id) then ( -}}
echo; echo '; https://github.com/docker-library/php/pull/725#issuecomment-443540114'; echo 'log_limit = 8192'; \
{{ ) else "" end -}}
echo; \
echo '[www]'; \
echo '; if we send this to /proc/self/fd/1, it never appears'; \
echo 'access.log = /proc/self/fd/2'; \
echo; \
echo 'clear_env = no'; \
echo; \
echo '; Ensure worker stdout and stderr are sent to the main error log.'; \
echo 'catch_workers_output = yes'; \
{{ if (.version | version_id) >= ("7.3" | version_id) then ( -}}
echo 'decorate_workers_output = no'; \
{{ ) else "" end -}}
} | tee php-fpm.d/docker.conf; \
{ \
echo '[global]'; \
echo 'daemonize = no'; \
echo; \
echo '[www]'; \
echo 'listen = 9000'; \
} | tee php-fpm.d/zz-docker.conf
# Override stop signal to stop process gracefully
# https://github.com/php/php-src/blob/17baa87faddc2550def3ae7314236826bc1b1398/sapi/fpm/php-fpm.8.in#L163
STOPSIGNAL SIGQUIT
EXPOSE 9000
{{ ) else "" end -}}
CMD {{ env.cmd }}