diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..9396a6bec9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +/*/**/Dockerfile linguist-generated +/*/**/docker-entrypoint.sh linguist-generated +/Dockerfile.template linguist-language=Dockerfile diff --git a/.github/workflows/verify-templating.yml b/.github/workflows/verify-templating.yml new file mode 100644 index 0000000000..7e833f1c7d --- /dev/null +++ b/.github/workflows/verify-templating.yml @@ -0,0 +1,22 @@ +name: Verify Templating + +on: + pull_request: + push: + +defaults: + run: + shell: 'bash -Eeuo pipefail -x {0}' + +jobs: + apply-templates: + name: Check For Uncomitted Changes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Apply Templates + run: ./apply-templates.sh + - name: Check Git Status + run: | + status="$(git status --short)" + [ -z "$status" ] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..d548f66de0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.jq-template.awk diff --git a/Dockerfile-cli.template b/Dockerfile-cli.template deleted file mode 100644 index 6de18f9859..0000000000 --- a/Dockerfile-cli.template +++ /dev/null @@ -1,101 +0,0 @@ -FROM php:%%PHP_VERSION%%-alpine - -# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) -RUN set -ex; \ - \ - apk add --no-cache --virtual .build-deps \ - $PHPIZE_DEPS \ - freetype-dev \ - imagemagick-dev \ - libjpeg-turbo-dev \ - libpng-dev \ - libzip-dev \ - ; \ - \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ - docker-php-ext-install -j "$(nproc)" \ - bcmath \ - exif \ - gd \ - mysqli \ - zip \ - ; \ - pecl install imagick-3.4.4; \ - docker-php-ext-enable imagick; \ - \ - runDeps="$( \ - scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ - | tr ',' '\n' \ - | sort -u \ - | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ - )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps - -# set recommended PHP.ini settings -# excluding opcache due https://github.com/docker-library/wordpress/issues/407 -# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging -RUN { \ -# https://www.php.net/manual/en/errorfunc.constants.php -# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 - echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ - echo 'display_errors = Off'; \ - echo 'display_startup_errors = Off'; \ - echo 'log_errors = On'; \ - echo 'error_log = /dev/stderr'; \ - echo 'log_errors_max_len = 1024'; \ - echo 'ignore_repeated_errors = On'; \ - echo 'ignore_repeated_source = Off'; \ - echo 'html_errors = Off'; \ - } > /usr/local/etc/php/conf.d/error-logging.ini - -# install wp-cli dependencies -RUN apk add --no-cache \ -# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 - bash \ - less \ - mysql-client - -RUN set -ex; \ - mkdir -p /var/www/html; \ - chown -R www-data:www-data /var/www/html -WORKDIR /var/www/html - -# https://make.wordpress.org/cli/2018/05/31/gpg-signature-change/ -# pub rsa2048 2018-05-31 [SC] -# 63AF 7AA1 5067 C056 16FD DD88 A3A2 E8F2 26F0 BC06 -# uid [ unknown] WP-CLI Releases -# sub rsa2048 2018-05-31 [E] -ENV WORDPRESS_CLI_GPG_KEY 63AF7AA15067C05616FDDD88A3A2E8F226F0BC06 - -ENV WORDPRESS_CLI_VERSION %%WORDPRESS_CLI_VERSION%% -ENV WORDPRESS_CLI_SHA512 %%WORDPRESS_CLI_SHA512%% - -RUN set -ex; \ - \ - apk add --no-cache --virtual .fetch-deps \ - gnupg \ - ; \ - \ - curl -o /usr/local/bin/wp.gpg -fSL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ - \ - export GNUPGHOME="$(mktemp -d)"; \ - gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$WORDPRESS_CLI_GPG_KEY"; \ - gpg --batch --decrypt --output /usr/local/bin/wp /usr/local/bin/wp.gpg; \ - command -v gpgconf && gpgconf --kill all || :; \ - rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; \ - \ - echo "$WORDPRESS_CLI_SHA512 */usr/local/bin/wp" | sha512sum -c -; \ - chmod +x /usr/local/bin/wp; \ - \ - apk del .fetch-deps; \ - \ - wp --allow-root --version - -VOLUME /var/www/html - -COPY docker-entrypoint.sh /usr/local/bin/ - -ENTRYPOINT ["docker-entrypoint.sh"] -USER www-data -CMD ["wp", "shell"] diff --git a/Dockerfile.template b/Dockerfile.template new file mode 100644 index 0000000000..705a21b462 --- /dev/null +++ b/Dockerfile.template @@ -0,0 +1,240 @@ +FROM php:{{ env.phpVersion }}-{{ env.variant }} + +{{ if env.version != "cli" then ( -}} +# persistent dependencies +{{ if env.variant | index("alpine") then ( -}} +RUN apk add --no-cache \ +# in theory, docker-entrypoint.sh is POSIX-compliant, but priority is a working, consistent image + bash \ +# BusyBox sed is not sufficient for some of our sed expressions + sed \ +# Ghostscript is required for rendering PDF previews + ghostscript \ +# Alpine package for "imagemagick" contains ~120 .so files, see: https://github.com/docker-library/wordpress/pull/497 + imagemagick +{{ ) else ( -}} +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ +# Ghostscript is required for rendering PDF previews + ghostscript \ + ; \ + rm -rf /var/lib/apt/lists/* +{{ ) end -}} +{{ ) else ( -}} +# install wp-cli dependencies +RUN apk add --no-cache \ +# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 + bash \ + less \ + mysql-client + +RUN set -ex; \ + mkdir -p /var/www/html; \ + chown -R www-data:www-data /var/www/html +WORKDIR /var/www/html +{{ ) end -}} + +# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) +RUN set -ex; \ + \ +{{ if env.variant | index("alpine") then ( -}} + apk add --no-cache --virtual .build-deps \ + $PHPIZE_DEPS \ + freetype-dev \ + imagemagick-dev \ + libjpeg-turbo-dev \ + libpng-dev \ + libzip-dev \ + ; \ +{{ ) else ( -}} + savedAptMark="$(apt-mark showmanual)"; \ + \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + libfreetype6-dev \ + libjpeg-dev \ + libmagickwand-dev \ + libpng-dev \ + libzip-dev \ + ; \ +{{ ) end -}} + \ + docker-php-ext-configure gd \ +{{ if env.phpVersion == "7.3" then ( -}} + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ +{{ ) else ( -}} + --with-freetype \ + --with-jpeg \ +{{ ) end -}} + ; \ + docker-php-ext-install -j "$(nproc)" \ + bcmath \ + exif \ + gd \ + mysqli \ + zip \ + ; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + \ +{{ if env.variant | index("alpine") then ( -}} + runDeps="$( \ + scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ + | tr ',' '\n' \ + | sort -u \ + | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ + )"; \ + apk add --no-network --virtual .wordpress-phpexts-rundeps $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; \ + apt-mark manual $savedAptMark; \ + ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ + | awk '/=>/ { print $3 }' \ + | sort -u \ + | xargs -r dpkg-query -S \ + | cut -d: -f1 \ + | sort -u \ + | xargs -rt apt-mark manual; \ + \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + rm -rf /var/lib/apt/lists/* +{{ ) end -}} + +# set recommended PHP.ini settings +{{ if env.version != "cli" then ( -}} +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +{{ ) else ( -}} +# excluding opcache due https://github.com/docker-library/wordpress/issues/407 +{{ ) end -}} +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini +{{ if env.variant == "apache" then ( -}} + +RUN set -eux; \ + a2enmod rewrite expires; \ + \ +# https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html + a2enmod remoteip; \ + { \ + echo 'RemoteIPHeader X-Forwarded-For'; \ +# these IP ranges are reserved for "private" use and should thus *usually* be safe inside Docker + echo 'RemoteIPTrustedProxy 10.0.0.0/8'; \ + echo 'RemoteIPTrustedProxy 172.16.0.0/12'; \ + echo 'RemoteIPTrustedProxy 192.168.0.0/16'; \ + echo 'RemoteIPTrustedProxy 169.254.0.0/16'; \ + echo 'RemoteIPTrustedProxy 127.0.0.0/8'; \ + } > /etc/apache2/conf-available/remoteip.conf; \ + a2enconf remoteip; \ +# https://github.com/docker-library/wordpress/issues/383#issuecomment-507886512 +# (replace all instances of "%h" with "%a" in LogFormat) + find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + +{{ ) else "" end -}} + +{{ if env.version != "cli" then ( -}} +RUN set -eux; \ + version={{ .upstream | @sh }}; \ + sha1={{ .sha1 | @sh }}; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ + chown -R www-data:www-data /usr/src/wordpress; \ +# pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root +# wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 + mkdir wp-content; \ + for dir in /usr/src/wordpress/wp-content/*/ cache; do \ + dir="$(basename "${dir%/}")"; \ + mkdir "wp-content/$dir"; \ + done; \ + chown -R www-data:www-data wp-content; \ + chmod -R 777 wp-content +{{ ) else ( -}} +# https://make.wordpress.org/cli/2018/05/31/gpg-signature-change/ +# pub rsa2048 2018-05-31 [SC] +# 63AF 7AA1 5067 C056 16FD DD88 A3A2 E8F2 26F0 BC06 +# uid [ unknown] WP-CLI Releases +# sub rsa2048 2018-05-31 [E] +ENV WORDPRESS_CLI_GPG_KEY 63AF7AA15067C05616FDDD88A3A2E8F226F0BC06 + +ENV WORDPRESS_CLI_VERSION {{ .version }} +ENV WORDPRESS_CLI_SHA512 {{ .sha512 }} + +RUN set -ex; \ + \ + apk add --no-cache --virtual .fetch-deps \ + gnupg \ + ; \ + \ + curl -o /usr/local/bin/wp.gpg -fL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ + \ + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; \ + gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$WORDPRESS_CLI_GPG_KEY"; \ + gpg --batch --decrypt --output /usr/local/bin/wp /usr/local/bin/wp.gpg; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; unset GNUPGHOME; \ + \ + echo "$WORDPRESS_CLI_SHA512 */usr/local/bin/wp" | sha512sum -c -; \ + chmod +x /usr/local/bin/wp; \ + \ + apk del --no-network .fetch-deps; \ + \ + wp --allow-root --version +{{ ) end -}} + +VOLUME /var/www/html + +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] +{{ if env.version != "cli" then ( -}} +CMD {{ [ if env.variant == "apache" then "apache2-foreground" else "php-fpm" end ] | @json }} +{{ ) else ( -}} +USER www-data +CMD ["wp", "shell"] +{{ ) end -}} diff --git a/apache-extras.template b/apache-extras.template deleted file mode 100644 index 9903a738d2..0000000000 --- a/apache-extras.template +++ /dev/null @@ -1,18 +0,0 @@ -RUN set -eux; \ - a2enmod rewrite expires; \ - \ -# https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html - a2enmod remoteip; \ - { \ - echo 'RemoteIPHeader X-Forwarded-For'; \ -# these IP ranges are reserved for "private" use and should thus *usually* be safe inside Docker - echo 'RemoteIPTrustedProxy 10.0.0.0/8'; \ - echo 'RemoteIPTrustedProxy 172.16.0.0/12'; \ - echo 'RemoteIPTrustedProxy 192.168.0.0/16'; \ - echo 'RemoteIPTrustedProxy 169.254.0.0/16'; \ - echo 'RemoteIPTrustedProxy 127.0.0.0/8'; \ - } > /etc/apache2/conf-available/remoteip.conf; \ - a2enconf remoteip; \ -# https://github.com/docker-library/wordpress/issues/383#issuecomment-507886512 -# (replace all instances of "%h" with "%a" in LogFormat) - find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + diff --git a/apply-templates.sh b/apply-templates.sh new file mode 100755 index 0000000000..ed3ad604ce --- /dev/null +++ b/apply-templates.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +[ -f versions.json ] # run "versions.sh" first + +jqt='.jq-template.awk' +if [ -n "${BASHBREW_SCRIPTS:-}" ]; then + jqt="$BASHBREW_SCRIPTS/jq-template.awk" +elif [ "$BASH_SOURCE" -nt "$jqt" ]; then + wget -qO "$jqt" 'https://github.com/docker-library/bashbrew/raw/5f0c26381fb7cc78b2d217d58007800bdcfbcfa1/scripts/jq-template.awk' +fi + +if [ "$#" -eq 0 ]; then + versions="$(jq -r 'keys | map(@sh) | join(" ")' versions.json)" + eval "set -- $versions" +fi + +generated_warning() { + cat <<-EOH + # + # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" + # + # PLEASE DO NOT EDIT IT DIRECTLY. + # + + EOH +} + +for version; do + export version + + phpVersions="$(jq -r '.[env.version].phpVersions | map(@sh) | join(" ")' versions.json)" + eval "phpVersions=( $phpVersions )" + variants="$(jq -r '.[env.version].variants | map(@sh) | join(" ")' versions.json)" + eval "variants=( $variants )" + + for phpVersion in "${phpVersions[@]}"; do + export phpVersion + + for variant in "${variants[@]}"; do + export variant + + dir="$version/php$phpVersion/$variant" + mkdir -p "$dir" + + echo "processing $dir ..." + + { + generated_warning + gawk -f "$jqt" Dockerfile.template + } > "$dir/Dockerfile" + + if [ "$version" = 'cli' ]; then + cp -a cli-entrypoint.sh "$dir/docker-entrypoint.sh" + else + cp -a docker-entrypoint.sh "$dir/" + fi + done + done +done diff --git a/beta/php7.3/apache/Dockerfile b/beta/php7.3/apache/Dockerfile new file mode 100644 index 0000000000..76401c5b13 --- /dev/null +++ b/beta/php7.3/apache/Dockerfile @@ -0,0 +1,149 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-apache + +# persistent dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ +# Ghostscript is required for rendering PDF previews + ghostscript \ + ; \ + rm -rf /var/lib/apt/lists/* + +# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) +RUN set -ex; \ + \ + savedAptMark="$(apt-mark showmanual)"; \ + \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + libfreetype6-dev \ + libjpeg-dev \ + libmagickwand-dev \ + libpng-dev \ + libzip-dev \ + ; \ + \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ + docker-php-ext-install -j "$(nproc)" \ + bcmath \ + exif \ + gd \ + mysqli \ + zip \ + ; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies + apt-mark auto '.*' > /dev/null; \ + apt-mark manual $savedAptMark; \ + ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ + | awk '/=>/ { print $3 }' \ + | sort -u \ + | xargs -r dpkg-query -S \ + | cut -d: -f1 \ + | sort -u \ + | xargs -rt apt-mark manual; \ + \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + rm -rf /var/lib/apt/lists/* + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini + +RUN set -eux; \ + a2enmod rewrite expires; \ + \ +# https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html + a2enmod remoteip; \ + { \ + echo 'RemoteIPHeader X-Forwarded-For'; \ +# these IP ranges are reserved for "private" use and should thus *usually* be safe inside Docker + echo 'RemoteIPTrustedProxy 10.0.0.0/8'; \ + echo 'RemoteIPTrustedProxy 172.16.0.0/12'; \ + echo 'RemoteIPTrustedProxy 192.168.0.0/16'; \ + echo 'RemoteIPTrustedProxy 169.254.0.0/16'; \ + echo 'RemoteIPTrustedProxy 127.0.0.0/8'; \ + } > /etc/apache2/conf-available/remoteip.conf; \ + a2enconf remoteip; \ +# https://github.com/docker-library/wordpress/issues/383#issuecomment-507886512 +# (replace all instances of "%h" with "%a" in LogFormat) + find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + + +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ + chown -R www-data:www-data /usr/src/wordpress; \ +# pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root +# wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 + mkdir wp-content; \ + for dir in /usr/src/wordpress/wp-content/*/ cache; do \ + dir="$(basename "${dir%/}")"; \ + mkdir "wp-content/$dir"; \ + done; \ + chown -R www-data:www-data wp-content; \ + chmod -R 777 wp-content + +VOLUME /var/www/html + +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/php7.3/apache/docker-entrypoint.sh b/beta/php7.3/apache/docker-entrypoint.sh similarity index 95% rename from php7.3/apache/docker-entrypoint.sh rename to beta/php7.3/apache/docker-entrypoint.sh index 8878d3e919..6a40c02b5f 100755 --- a/php7.3/apache/docker-entrypoint.sh +++ b/beta/php7.3/apache/docker-entrypoint.sh @@ -82,22 +82,6 @@ if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then done tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi fi # allow any of these "Authentication Unique Keys and Salts." to be specified via diff --git a/Dockerfile-alpine.template b/beta/php7.3/fpm-alpine/Dockerfile similarity index 73% rename from Dockerfile-alpine.template rename to beta/php7.3/fpm-alpine/Dockerfile index e7cb288e88..faa5697569 100644 --- a/Dockerfile-alpine.template +++ b/beta/php7.3/fpm-alpine/Dockerfile @@ -1,4 +1,10 @@ -FROM php:%%PHP_VERSION%%-%%VARIANT%% +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-fpm-alpine # persistent dependencies RUN apk add --no-cache \ @@ -23,7 +29,11 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -40,8 +50,8 @@ RUN set -ex; \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps # set recommended PHP.ini settings # see https://secure.php.net/manual/en/opcache.installation.php @@ -68,17 +78,34 @@ RUN { \ echo 'ignore_repeated_source = Off'; \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini -%%VARIANT_EXTRAS%% - -ENV WORDPRESS_VERSION %%WORDPRESS_VERSION%% -ENV WORDPRESS_SHA1 %%WORDPRESS_SHA1%% -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 @@ -95,4 +122,4 @@ VOLUME /var/www/html COPY docker-entrypoint.sh /usr/local/bin/ ENTRYPOINT ["docker-entrypoint.sh"] -CMD ["%%CMD%%"] +CMD ["php-fpm"] diff --git a/php7.3/fpm-alpine/docker-entrypoint.sh b/beta/php7.3/fpm-alpine/docker-entrypoint.sh similarity index 95% rename from php7.3/fpm-alpine/docker-entrypoint.sh rename to beta/php7.3/fpm-alpine/docker-entrypoint.sh index 8878d3e919..6a40c02b5f 100755 --- a/php7.3/fpm-alpine/docker-entrypoint.sh +++ b/beta/php7.3/fpm-alpine/docker-entrypoint.sh @@ -82,22 +82,6 @@ if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then done tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi fi # allow any of these "Authentication Unique Keys and Salts." to be specified via diff --git a/Dockerfile-debian.template b/beta/php7.3/fpm/Dockerfile similarity index 75% rename from Dockerfile-debian.template rename to beta/php7.3/fpm/Dockerfile index 8fd9417cda..4351bc44f5 100644 --- a/Dockerfile-debian.template +++ b/beta/php7.3/fpm/Dockerfile @@ -1,4 +1,10 @@ -FROM php:%%PHP_VERSION%%-%%VARIANT%% +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-fpm # persistent dependencies RUN set -eux; \ @@ -23,7 +29,11 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -73,17 +83,34 @@ RUN { \ echo 'ignore_repeated_source = Off'; \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini -%%VARIANT_EXTRAS%% - -ENV WORDPRESS_VERSION %%WORDPRESS_VERSION%% -ENV WORDPRESS_SHA1 %%WORDPRESS_SHA1%% -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 @@ -100,4 +127,4 @@ VOLUME /var/www/html COPY docker-entrypoint.sh /usr/local/bin/ ENTRYPOINT ["docker-entrypoint.sh"] -CMD ["%%CMD%%"] +CMD ["php-fpm"] diff --git a/php7.3/fpm/docker-entrypoint.sh b/beta/php7.3/fpm/docker-entrypoint.sh similarity index 95% rename from php7.3/fpm/docker-entrypoint.sh rename to beta/php7.3/fpm/docker-entrypoint.sh index 8878d3e919..6a40c02b5f 100755 --- a/php7.3/fpm/docker-entrypoint.sh +++ b/beta/php7.3/fpm/docker-entrypoint.sh @@ -82,22 +82,6 @@ if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then done tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi fi # allow any of these "Authentication Unique Keys and Salts." to be specified via diff --git a/php7.4/apache/Dockerfile b/beta/php7.4/apache/Dockerfile similarity index 81% rename from php7.4/apache/Dockerfile rename to beta/php7.4/apache/Dockerfile index a11927bd0f..23ea62dc82 100644 --- a/php7.4/apache/Dockerfile +++ b/beta/php7.4/apache/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM php:7.4-apache # persistent dependencies @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -93,16 +102,33 @@ RUN set -eux; \ # (replace all instances of "%h" with "%a" in LogFormat) find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/php7.4/apache/docker-entrypoint.sh b/beta/php7.4/apache/docker-entrypoint.sh similarity index 95% rename from php7.4/apache/docker-entrypoint.sh rename to beta/php7.4/apache/docker-entrypoint.sh index 8878d3e919..6a40c02b5f 100755 --- a/php7.4/apache/docker-entrypoint.sh +++ b/beta/php7.4/apache/docker-entrypoint.sh @@ -82,22 +82,6 @@ if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then done tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi fi # allow any of these "Authentication Unique Keys and Salts." to be specified via diff --git a/php7.4/fpm-alpine/Dockerfile b/beta/php7.4/fpm-alpine/Dockerfile similarity index 74% rename from php7.4/fpm-alpine/Dockerfile rename to beta/php7.4/fpm-alpine/Dockerfile index e0c1f9d5eb..6c2ed0f856 100644 --- a/php7.4/fpm-alpine/Dockerfile +++ b/beta/php7.4/fpm-alpine/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM php:7.4-fpm-alpine # persistent dependencies @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -40,8 +49,8 @@ RUN set -ex; \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps # set recommended PHP.ini settings # see https://secure.php.net/manual/en/opcache.installation.php @@ -69,16 +78,33 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/beta/php7.4/fpm-alpine/docker-entrypoint.sh b/beta/php7.4/fpm-alpine/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/beta/php7.4/fpm-alpine/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.4/fpm/Dockerfile b/beta/php7.4/fpm/Dockerfile similarity index 77% rename from php7.4/fpm/Dockerfile rename to beta/php7.4/fpm/Dockerfile index f6c98acdf3..6f3e92224f 100644 --- a/php7.4/fpm/Dockerfile +++ b/beta/php7.4/fpm/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM php:7.4-fpm # persistent dependencies @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -74,16 +83,33 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/beta/php7.4/fpm/docker-entrypoint.sh b/beta/php7.4/fpm/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/beta/php7.4/fpm/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.3/cli/Dockerfile b/cli/php7.3/alpine/Dockerfile similarity index 81% rename from php7.3/cli/Dockerfile rename to cli/php7.3/alpine/Dockerfile index b9d56a1bb6..b05e59adc0 100644 --- a/php7.3/cli/Dockerfile +++ b/cli/php7.3/alpine/Dockerfile @@ -1,5 +1,23 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM php:7.3-alpine +# install wp-cli dependencies +RUN apk add --no-cache \ +# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 + bash \ + less \ + mysql-client + +RUN set -ex; \ + mkdir -p /var/www/html; \ + chown -R www-data:www-data /var/www/html +WORKDIR /var/www/html + # install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) RUN set -ex; \ \ @@ -12,7 +30,11 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr; \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -29,8 +51,8 @@ RUN set -ex; \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps # set recommended PHP.ini settings # excluding opcache due https://github.com/docker-library/wordpress/issues/407 @@ -49,18 +71,6 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini -# install wp-cli dependencies -RUN apk add --no-cache \ -# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 - bash \ - less \ - mysql-client - -RUN set -ex; \ - mkdir -p /var/www/html; \ - chown -R www-data:www-data /var/www/html -WORKDIR /var/www/html - # https://make.wordpress.org/cli/2018/05/31/gpg-signature-change/ # pub rsa2048 2018-05-31 [SC] # 63AF 7AA1 5067 C056 16FD DD88 A3A2 E8F2 26F0 BC06 @@ -77,18 +87,18 @@ RUN set -ex; \ gnupg \ ; \ \ - curl -o /usr/local/bin/wp.gpg -fSL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ + curl -o /usr/local/bin/wp.gpg -fL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ \ - export GNUPGHOME="$(mktemp -d)"; \ + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; \ gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$WORDPRESS_CLI_GPG_KEY"; \ gpg --batch --decrypt --output /usr/local/bin/wp /usr/local/bin/wp.gpg; \ - command -v gpgconf && gpgconf --kill all || :; \ - rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; unset GNUPGHOME; \ \ echo "$WORDPRESS_CLI_SHA512 */usr/local/bin/wp" | sha512sum -c -; \ chmod +x /usr/local/bin/wp; \ \ - apk del .fetch-deps; \ + apk del --no-network .fetch-deps; \ \ wp --allow-root --version diff --git a/php7.3/cli/docker-entrypoint.sh b/cli/php7.3/alpine/docker-entrypoint.sh similarity index 100% rename from php7.3/cli/docker-entrypoint.sh rename to cli/php7.3/alpine/docker-entrypoint.sh diff --git a/php7.4/cli/Dockerfile b/cli/php7.4/alpine/Dockerfile similarity index 82% rename from php7.4/cli/Dockerfile rename to cli/php7.4/alpine/Dockerfile index 4e784dd0f0..5902fe7e9c 100644 --- a/php7.4/cli/Dockerfile +++ b/cli/php7.4/alpine/Dockerfile @@ -1,5 +1,23 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM php:7.4-alpine +# install wp-cli dependencies +RUN apk add --no-cache \ +# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 + bash \ + less \ + mysql-client + +RUN set -ex; \ + mkdir -p /var/www/html; \ + chown -R www-data:www-data /var/www/html +WORKDIR /var/www/html + # install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) RUN set -ex; \ \ @@ -12,7 +30,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype --with-jpeg; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -29,8 +50,8 @@ RUN set -ex; \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps # set recommended PHP.ini settings # excluding opcache due https://github.com/docker-library/wordpress/issues/407 @@ -49,18 +70,6 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini -# install wp-cli dependencies -RUN apk add --no-cache \ -# bash is needed for 'wp shell': https://github.com/wp-cli/shell-command/blob/b8dafcc2a2eba5732fdee70be077675a302848e9/src/WP_CLI/REPL.php#L104 - bash \ - less \ - mysql-client - -RUN set -ex; \ - mkdir -p /var/www/html; \ - chown -R www-data:www-data /var/www/html -WORKDIR /var/www/html - # https://make.wordpress.org/cli/2018/05/31/gpg-signature-change/ # pub rsa2048 2018-05-31 [SC] # 63AF 7AA1 5067 C056 16FD DD88 A3A2 E8F2 26F0 BC06 @@ -77,18 +86,18 @@ RUN set -ex; \ gnupg \ ; \ \ - curl -o /usr/local/bin/wp.gpg -fSL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ + curl -o /usr/local/bin/wp.gpg -fL "https://github.com/wp-cli/wp-cli/releases/download/v${WORDPRESS_CLI_VERSION}/wp-cli-${WORDPRESS_CLI_VERSION}.phar.gpg"; \ \ - export GNUPGHOME="$(mktemp -d)"; \ + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; \ gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$WORDPRESS_CLI_GPG_KEY"; \ gpg --batch --decrypt --output /usr/local/bin/wp /usr/local/bin/wp.gpg; \ - command -v gpgconf && gpgconf --kill all || :; \ - rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; \ + gpgconf --kill all; \ + rm -rf "$GNUPGHOME" /usr/local/bin/wp.gpg; unset GNUPGHOME; \ \ echo "$WORDPRESS_CLI_SHA512 */usr/local/bin/wp" | sha512sum -c -; \ chmod +x /usr/local/bin/wp; \ \ - apk del .fetch-deps; \ + apk del --no-network .fetch-deps; \ \ wp --allow-root --version diff --git a/php7.4/cli/docker-entrypoint.sh b/cli/php7.4/alpine/docker-entrypoint.sh similarity index 100% rename from php7.4/cli/docker-entrypoint.sh rename to cli/php7.4/alpine/docker-entrypoint.sh diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 8878d3e919..6a40c02b5f 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -82,22 +82,6 @@ if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then done tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi fi # allow any of these "Authentication Unique Keys and Salts." to be specified via diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index a70964e40c..8ca2c547a4 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -1,5 +1,5 @@ -#!/bin/bash -set -eu +#!/usr/bin/env bash +set -Eeuo pipefail # https://wordpress.org/about/requirements/ # https://wordpress.org/support/update-php/#before-you-update-your-php-version @@ -9,8 +9,13 @@ defaultVariant='apache' self="$(basename "$BASH_SOURCE")" cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" -phpVersions=( php*.*/ ) -phpVersions=( "${phpVersions[@]%/}" ) +if [ "$#" -eq 0 ]; then + versions="$(jq -r 'keys | map(@sh) | join(" ")' versions.json)" + eval "set -- $versions" +fi + +# make sure "latest" is first and "beta" is last +IFS=$'\n'; set -- $(tac <<<"$*"); unset IFS # get the most recent commit which modified any of "$@" fileCommit() { @@ -65,80 +70,20 @@ join() { echo "${out#$sep}" } -for phpVersion in "${phpVersions[@]}"; do - for variant in apache fpm fpm-alpine; do - dir="$phpVersion/$variant" - [ -f "$dir/Dockerfile" ] || continue - - commit="$(dirCommit "$dir")" - - fullVersion="$(git show "$commit":"$dir/Dockerfile" | awk '$1 == "ENV" && $2 == "WORDPRESS_VERSION" { print $3; exit }')" - if [[ "$fullVersion" != *.*.* && "$fullVersion" == *.* ]]; then - fullVersion+='.0' - fi - - versionAliases=() - while [ "${fullVersion%[.-]*}" != "$fullVersion" ]; do - versionAliases+=( $fullVersion ) - fullVersion="${fullVersion%[.-]*}" - done - versionAliases+=( - $fullVersion - latest - ) - - phpVersionAliases=( "${versionAliases[@]/%/-$phpVersion}" ) - phpVersionAliases=( "${phpVersionAliases[@]//latest-/}" ) - - variantAliases=( "${versionAliases[@]/%/-$variant}" ) - variantAliases=( "${variantAliases[@]//latest-/}" ) +for version; do + export version - phpVersionVariantAliases=( "${versionAliases[@]/%/-$phpVersion-$variant}" ) - phpVersionVariantAliases=( "${phpVersionVariantAliases[@]//latest-/}" ) - - fullAliases=() - - if [ "$phpVersion" = "$defaultPhpVersion" ]; then - fullAliases+=( "${variantAliases[@]}" ) - - if [ "$variant" = "$defaultVariant" ]; then - fullAliases+=( "${versionAliases[@]}" ) - fi - fi - - fullAliases+=( - "${phpVersionVariantAliases[@]}" - ) - - if [ "$variant" = "$defaultVariant" ]; then - fullAliases+=( "${phpVersionAliases[@]}" ) - fi - - variantParent="$(awk 'toupper($1) == "FROM" { print $2 }' "$dir/Dockerfile")" - variantArches="${parentRepoToArches[$variantParent]}" - - echo - cat <<-EOE - Tags: $(join ', ' "${fullAliases[@]}") - Architectures: $(join ', ' $variantArches) - GitCommit: $commit - Directory: $dir - EOE - done -done + phpVersions="$(jq -r '.[env.version].phpVersions | map(@sh) | join(" ")' versions.json)" + eval "phpVersions=( $phpVersions )" + variants="$(jq -r '.[env.version].variants | map(@sh) | join(" ")' versions.json)" + eval "variants=( $variants )" -echo -echo '# Now, wp-cli variants (which do _not_ include WordPress, so no WordPress version number -- only wp-cli version)' + fullVersion="$(jq -r '.[env.version].version' versions.json)" -for phpVersion in "${phpVersions[@]}"; do - variant='cli' - - dir="$phpVersion/$variant" - [ -f "$dir/Dockerfile" ] || continue - - commit="$(dirCommit "$dir")" - - fullVersion="$(git show "$commit":"$dir/Dockerfile" | awk '$1 == "ENV" && $2 == "WORDPRESS_CLI_VERSION" { print $3; exit }')" + if [ "$version" = 'beta' ] && latestVersion="$(jq -r '.latest.version // ""' versions.json)" && [ "$latestVersion" = "$fullVersion" ]; then + # "beta" channel even with release, skip it + continue + fi versionAliases=() while [ "${fullVersion%[.-]*}" != "$fullVersion" ]; do @@ -150,34 +95,59 @@ for phpVersion in "${phpVersions[@]}"; do latest ) - phpVersionAliases=( "${versionAliases[@]/#/$phpVersion-}" ) - phpVersionAliases=( "${phpVersionAliases[@]//-latest/}" ) + for phpVersion in "${phpVersions[@]}"; do + phpVersion="php$phpVersion" + for variant in "${variants[@]}"; do + dir="$version/$phpVersion/$variant" + [ -f "$dir/Dockerfile" ] || continue - variantAliases=( "${versionAliases[@]/#/$variant-}" ) - variantAliases=( "${variantAliases[@]//-latest/}" ) + commit="$(dirCommit "$dir")" - phpVersionVariantAliases=( "${versionAliases[@]/#/$variant-}" ) - phpVersionVariantAliases=( "${phpVersionVariantAliases[@]//-latest/}" ) - phpVersionVariantAliases=( "${phpVersionVariantAliases[@]/%/-$phpVersion}" ) + phpVersionAliases=( "${versionAliases[@]/%/-$phpVersion}" ) + phpVersionAliases=( "${phpVersionAliases[@]//latest-/}" ) - fullAliases=() + if [ "$version" != 'cli' ]; then + variantAliases=( "${versionAliases[@]/%/-$variant}" ) + variantAliases=( "${variantAliases[@]//latest-/}" ) - if [ "$phpVersion" = "$defaultPhpVersion" ]; then - fullAliases+=( "${variantAliases[@]}" ) - fi + phpVersionVariantAliases=( "${versionAliases[@]/%/-$phpVersion-$variant}" ) + phpVersionVariantAliases=( "${phpVersionVariantAliases[@]//latest-/}" ) + fi - fullAliases+=( - "${phpVersionVariantAliases[@]}" - ) + fullAliases=() + if [ "$version" != 'cli' ]; then + if [ "$phpVersion" = "$defaultPhpVersion" ]; then + fullAliases+=( "${variantAliases[@]}" ) + if [ "$variant" = "$defaultVariant" ]; then + fullAliases+=( "${versionAliases[@]}" ) + fi + fi + fullAliases+=( "${phpVersionVariantAliases[@]}" ) + if [ "$variant" = "$defaultVariant" ]; then + fullAliases+=( "${phpVersionAliases[@]}" ) + fi + else + if [ "$phpVersion" = "$defaultPhpVersion" ]; then + fullAliases+=( "${versionAliases[@]}" ) + fi + fullAliases+=( "${phpVersionAliases[@]}" ) + fi + + if [ "$version" != 'latest' ]; then + fullAliases=( "${fullAliases[@]/#/$version-}" ) + fullAliases=( "${fullAliases[@]//-latest/}" ) + fi - variantParent="$(awk 'toupper($1) == "FROM" { print $2 }' "$dir/Dockerfile")" - variantArches="${parentRepoToArches[$variantParent]}" + variantParent="$(awk 'toupper($1) == "FROM" { print $2 }' "$dir/Dockerfile")" + variantArches="${parentRepoToArches[$variantParent]}" - echo - cat <<-EOE - Tags: $(join ', ' "${fullAliases[@]}") - Architectures: $(join ', ' $variantArches) - GitCommit: $commit - Directory: $dir - EOE + echo + cat <<-EOE + Tags: $(join ', ' "${fullAliases[@]}") + Architectures: $(join ', ' $variantArches) + GitCommit: $commit + Directory: $dir + EOE + done + done done diff --git a/latest/php7.3/apache/Dockerfile b/latest/php7.3/apache/Dockerfile new file mode 100644 index 0000000000..76401c5b13 --- /dev/null +++ b/latest/php7.3/apache/Dockerfile @@ -0,0 +1,149 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-apache + +# persistent dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ +# Ghostscript is required for rendering PDF previews + ghostscript \ + ; \ + rm -rf /var/lib/apt/lists/* + +# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) +RUN set -ex; \ + \ + savedAptMark="$(apt-mark showmanual)"; \ + \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + libfreetype6-dev \ + libjpeg-dev \ + libmagickwand-dev \ + libpng-dev \ + libzip-dev \ + ; \ + \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ + docker-php-ext-install -j "$(nproc)" \ + bcmath \ + exif \ + gd \ + mysqli \ + zip \ + ; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies + apt-mark auto '.*' > /dev/null; \ + apt-mark manual $savedAptMark; \ + ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ + | awk '/=>/ { print $3 }' \ + | sort -u \ + | xargs -r dpkg-query -S \ + | cut -d: -f1 \ + | sort -u \ + | xargs -rt apt-mark manual; \ + \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + rm -rf /var/lib/apt/lists/* + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini + +RUN set -eux; \ + a2enmod rewrite expires; \ + \ +# https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html + a2enmod remoteip; \ + { \ + echo 'RemoteIPHeader X-Forwarded-For'; \ +# these IP ranges are reserved for "private" use and should thus *usually* be safe inside Docker + echo 'RemoteIPTrustedProxy 10.0.0.0/8'; \ + echo 'RemoteIPTrustedProxy 172.16.0.0/12'; \ + echo 'RemoteIPTrustedProxy 192.168.0.0/16'; \ + echo 'RemoteIPTrustedProxy 169.254.0.0/16'; \ + echo 'RemoteIPTrustedProxy 127.0.0.0/8'; \ + } > /etc/apache2/conf-available/remoteip.conf; \ + a2enconf remoteip; \ +# https://github.com/docker-library/wordpress/issues/383#issuecomment-507886512 +# (replace all instances of "%h" with "%a" in LogFormat) + find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + + +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ + chown -R www-data:www-data /usr/src/wordpress; \ +# pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root +# wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 + mkdir wp-content; \ + for dir in /usr/src/wordpress/wp-content/*/ cache; do \ + dir="$(basename "${dir%/}")"; \ + mkdir "wp-content/$dir"; \ + done; \ + chown -R www-data:www-data wp-content; \ + chmod -R 777 wp-content + +VOLUME /var/www/html + +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/latest/php7.3/apache/docker-entrypoint.sh b/latest/php7.3/apache/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.3/apache/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/latest/php7.3/fpm-alpine/Dockerfile b/latest/php7.3/fpm-alpine/Dockerfile new file mode 100644 index 0000000000..faa5697569 --- /dev/null +++ b/latest/php7.3/fpm-alpine/Dockerfile @@ -0,0 +1,125 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-fpm-alpine + +# persistent dependencies +RUN apk add --no-cache \ +# in theory, docker-entrypoint.sh is POSIX-compliant, but priority is a working, consistent image + bash \ +# BusyBox sed is not sufficient for some of our sed expressions + sed \ +# Ghostscript is required for rendering PDF previews + ghostscript \ +# Alpine package for "imagemagick" contains ~120 .so files, see: https://github.com/docker-library/wordpress/pull/497 + imagemagick + +# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) +RUN set -ex; \ + \ + apk add --no-cache --virtual .build-deps \ + $PHPIZE_DEPS \ + freetype-dev \ + imagemagick-dev \ + libjpeg-turbo-dev \ + libpng-dev \ + libzip-dev \ + ; \ + \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ + docker-php-ext-install -j "$(nproc)" \ + bcmath \ + exif \ + gd \ + mysqli \ + zip \ + ; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + \ + runDeps="$( \ + scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ + | tr ',' '\n' \ + | sort -u \ + | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ + )"; \ + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini + +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ + chown -R www-data:www-data /usr/src/wordpress; \ +# pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root +# wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 + mkdir wp-content; \ + for dir in /usr/src/wordpress/wp-content/*/ cache; do \ + dir="$(basename "${dir%/}")"; \ + mkdir "wp-content/$dir"; \ + done; \ + chown -R www-data:www-data wp-content; \ + chmod -R 777 wp-content + +VOLUME /var/www/html + +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["php-fpm"] diff --git a/latest/php7.3/fpm-alpine/docker-entrypoint.sh b/latest/php7.3/fpm-alpine/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.3/fpm-alpine/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/latest/php7.3/fpm/Dockerfile b/latest/php7.3/fpm/Dockerfile new file mode 100644 index 0000000000..4351bc44f5 --- /dev/null +++ b/latest/php7.3/fpm/Dockerfile @@ -0,0 +1,130 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.3-fpm + +# persistent dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ +# Ghostscript is required for rendering PDF previews + ghostscript \ + ; \ + rm -rf /var/lib/apt/lists/* + +# install the PHP extensions we need (https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions) +RUN set -ex; \ + \ + savedAptMark="$(apt-mark showmanual)"; \ + \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + libfreetype6-dev \ + libjpeg-dev \ + libmagickwand-dev \ + libpng-dev \ + libzip-dev \ + ; \ + \ + docker-php-ext-configure gd \ + --with-freetype-dir=/usr \ + --with-jpeg-dir=/usr \ + --with-png-dir=/usr \ + ; \ + docker-php-ext-install -j "$(nproc)" \ + bcmath \ + exif \ + gd \ + mysqli \ + zip \ + ; \ + pecl install imagick-3.4.4; \ + docker-php-ext-enable imagick; \ + \ +# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies + apt-mark auto '.*' > /dev/null; \ + apt-mark manual $savedAptMark; \ + ldd "$(php -r 'echo ini_get("extension_dir");')"/*.so \ + | awk '/=>/ { print $3 }' \ + | sort -u \ + | xargs -r dpkg-query -S \ + | cut -d: -f1 \ + | sort -u \ + | xargs -rt apt-mark manual; \ + \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ + rm -rf /var/lib/apt/lists/* + +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini + +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ +# upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress + tar -xzf wordpress.tar.gz -C /usr/src/; \ + rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ + chown -R www-data:www-data /usr/src/wordpress; \ +# pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root +# wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 + mkdir wp-content; \ + for dir in /usr/src/wordpress/wp-content/*/ cache; do \ + dir="$(basename "${dir%/}")"; \ + mkdir "wp-content/$dir"; \ + done; \ + chown -R www-data:www-data wp-content; \ + chmod -R 777 wp-content + +VOLUME /var/www/html + +COPY docker-entrypoint.sh /usr/local/bin/ + +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["php-fpm"] diff --git a/latest/php7.3/fpm/docker-entrypoint.sh b/latest/php7.3/fpm/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.3/fpm/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.3/apache/Dockerfile b/latest/php7.4/apache/Dockerfile similarity index 80% rename from php7.3/apache/Dockerfile rename to latest/php7.4/apache/Dockerfile index d3666ef9bf..23ea62dc82 100644 --- a/php7.3/apache/Dockerfile +++ b/latest/php7.4/apache/Dockerfile @@ -1,4 +1,10 @@ -FROM php:7.3-apache +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.4-apache # persistent dependencies RUN set -eux; \ @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -93,16 +102,33 @@ RUN set -eux; \ # (replace all instances of "%h" with "%a" in LogFormat) find /etc/apache2 -type f -name '*.conf' -exec sed -ri 's/([[:space:]]*LogFormat[[:space:]]+"[^"]*)%h([^"]*")/\1%a\2/g' '{}' + - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/latest/php7.4/apache/docker-entrypoint.sh b/latest/php7.4/apache/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.4/apache/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.3/fpm-alpine/Dockerfile b/latest/php7.4/fpm-alpine/Dockerfile similarity index 74% rename from php7.3/fpm-alpine/Dockerfile rename to latest/php7.4/fpm-alpine/Dockerfile index 23b153649e..6c2ed0f856 100644 --- a/php7.3/fpm-alpine/Dockerfile +++ b/latest/php7.4/fpm-alpine/Dockerfile @@ -1,4 +1,10 @@ -FROM php:7.3-fpm-alpine +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.4-fpm-alpine # persistent dependencies RUN apk add --no-cache \ @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -40,8 +49,8 @@ RUN set -ex; \ | sort -u \ | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ )"; \ - apk add --virtual .wordpress-phpexts-rundeps $runDeps; \ - apk del .build-deps + apk add --no-network --virtual .wordpress-phpexts-rundeps $runDeps; \ + apk del --no-network .build-deps # set recommended PHP.ini settings # see https://secure.php.net/manual/en/opcache.installation.php @@ -69,16 +78,33 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/latest/php7.4/fpm-alpine/docker-entrypoint.sh b/latest/php7.4/fpm-alpine/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.4/fpm-alpine/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.3/fpm/Dockerfile b/latest/php7.4/fpm/Dockerfile similarity index 76% rename from php7.3/fpm/Dockerfile rename to latest/php7.4/fpm/Dockerfile index 5504dbaec7..6f3e92224f 100644 --- a/php7.3/fpm/Dockerfile +++ b/latest/php7.4/fpm/Dockerfile @@ -1,4 +1,10 @@ -FROM php:7.3-fpm +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM php:7.4-fpm # persistent dependencies RUN set -eux; \ @@ -23,7 +29,10 @@ RUN set -ex; \ libzip-dev \ ; \ \ - docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr; \ + docker-php-ext-configure gd \ + --with-freetype \ + --with-jpeg \ + ; \ docker-php-ext-install -j "$(nproc)" \ bcmath \ exif \ @@ -74,16 +83,33 @@ RUN { \ echo 'html_errors = Off'; \ } > /usr/local/etc/php/conf.d/error-logging.ini - -ENV WORDPRESS_VERSION 5.6 -ENV WORDPRESS_SHA1 db8b75bfc9de27490434b365c12fd805ca6784ce - -RUN set -ex; \ - curl -o wordpress.tar.gz -fSL "https://wordpress.org/wordpress-${WORDPRESS_VERSION}.tar.gz"; \ - echo "$WORDPRESS_SHA1 *wordpress.tar.gz" | sha1sum -c -; \ +RUN set -eux; \ + version='5.6'; \ + sha1='db8b75bfc9de27490434b365c12fd805ca6784ce'; \ + \ + curl -o wordpress.tar.gz -fL "https://wordpress.org/wordpress-$version.tar.gz"; \ + echo "$sha1 *wordpress.tar.gz" | sha1sum -c -; \ + \ # upstream tarballs include ./wordpress/ so this gives us /usr/src/wordpress tar -xzf wordpress.tar.gz -C /usr/src/; \ rm wordpress.tar.gz; \ + \ +# https://wordpress.org/support/article/htaccess/ + [ ! -e /usr/src/wordpress/.htaccess ]; \ + { \ + echo '# BEGIN WordPress'; \ + echo ''; \ + echo 'RewriteEngine On'; \ + echo 'RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]'; \ + echo 'RewriteBase /'; \ + echo 'RewriteRule ^index\.php$ - [L]'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-f'; \ + echo 'RewriteCond %{REQUEST_FILENAME} !-d'; \ + echo 'RewriteRule . /index.php [L]'; \ + echo ''; \ + echo '# END WordPress'; \ + } > /usr/src/wordpress/.htaccess; \ + \ chown -R www-data:www-data /usr/src/wordpress; \ # pre-create wp-content (and single-level children) for folks who want to bind-mount themes, etc so permissions are pre-created properly instead of root:root # wp-content/cache: https://github.com/docker-library/wordpress/issues/534#issuecomment-705733507 diff --git a/latest/php7.4/fpm/docker-entrypoint.sh b/latest/php7.4/fpm/docker-entrypoint.sh new file mode 100755 index 0000000000..6a40c02b5f --- /dev/null +++ b/latest/php7.4/fpm/docker-entrypoint.sh @@ -0,0 +1,285 @@ +#!/bin/bash +set -euo pipefail + +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + local val="$def" + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + export "$var"="$val" + unset "$fileVar" +} + +if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then + if [ "$(id -u)" = '0' ]; then + case "$1" in + apache2*) + user="${APACHE_RUN_USER:-www-data}" + group="${APACHE_RUN_GROUP:-www-data}" + + # strip off any '#' symbol ('#1000' is valid syntax for Apache) + pound='#' + user="${user#$pound}" + group="${group#$pound}" + ;; + *) # php-fpm + user='www-data' + group='www-data' + ;; + esac + else + user="$(id -u)" + group="$(id -g)" + fi + + if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then + # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) + if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then + chown "$user:$group" . + fi + + echo >&2 "WordPress not found in $PWD - copying now..." + if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then + echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" + fi + sourceTarArgs=( + --create + --file - + --directory /usr/src/wordpress + --owner "$user" --group "$group" + ) + targetTarArgs=( + --extract + --file - + ) + if [ "$user" != '0' ]; then + # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" + targetTarArgs+=( --no-overwrite-dir ) + fi + # loop over "pluggable" content in the source, and if it already exists in the destination, skip it + # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) + for contentDir in /usr/src/wordpress/wp-content/*/*/; do + contentDir="${contentDir%/}" + [ -d "$contentDir" ] || continue + contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. + if [ -d "$PWD/$contentPath" ]; then + echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" + sourceTarArgs+=( --exclude "./$contentPath" ) + fi + done + tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" + echo >&2 "Complete! WordPress has been successfully copied to $PWD" + fi + + # allow any of these "Authentication Unique Keys and Salts." to be specified via + # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") + uniqueEnvs=( + AUTH_KEY + SECURE_AUTH_KEY + LOGGED_IN_KEY + NONCE_KEY + AUTH_SALT + SECURE_AUTH_SALT + LOGGED_IN_SALT + NONCE_SALT + ) + envs=( + WORDPRESS_DB_HOST + WORDPRESS_DB_USER + WORDPRESS_DB_PASSWORD + WORDPRESS_DB_NAME + WORDPRESS_DB_CHARSET + WORDPRESS_DB_COLLATE + "${uniqueEnvs[@]/#/WORDPRESS_}" + WORDPRESS_TABLE_PREFIX + WORDPRESS_DEBUG + WORDPRESS_CONFIG_EXTRA + ) + haveConfig= + for e in "${envs[@]}"; do + file_env "$e" + if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then + haveConfig=1 + fi + done + + # linking backwards-compatibility + if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then + haveConfig=1 + # host defaults to "mysql" below if unspecified + : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" + if [ "$WORDPRESS_DB_USER" = 'root' ]; then + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" + else + : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" + fi + : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" + fi + + # only touch "wp-config.php" if we have environment-supplied configuration values + if [ "$haveConfig" ]; then + : "${WORDPRESS_DB_HOST:=mysql}" + : "${WORDPRESS_DB_USER:=root}" + : "${WORDPRESS_DB_PASSWORD:=}" + : "${WORDPRESS_DB_NAME:=wordpress}" + : "${WORDPRESS_DB_CHARSET:=utf8}" + : "${WORDPRESS_DB_COLLATE:=}" + + # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks + # https://github.com/docker-library/wordpress/issues/116 + # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 + sed -ri -e 's/\r$//' wp-config* + + if [ ! -e wp-config.php ]; then + awk ' + /^\/\*.*stop editing.*\*\/$/ && c == 0 { + c = 1 + system("cat") + if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { + print "// WORDPRESS_CONFIG_EXTRA" + print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" + } + } + { print } + ' wp-config-sample.php > wp-config.php <<'EOPHP' +// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact +// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy +if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + $_SERVER['HTTPS'] = 'on'; +} + +EOPHP + chown "$user:$group" wp-config.php + elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then + # (if the config file already contains the requested PHP code, don't print a warning) + echo >&2 + echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' + echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' + echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' + echo >&2 + fi + + # see http://stackoverflow.com/a/2705678/433558 + sed_escape_lhs() { + echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' + } + sed_escape_rhs() { + echo "$@" | sed -e 's/[\/&]/\\&/g' + } + php_escape() { + local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" + if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then + escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" + fi + echo "$escaped" + } + set_config() { + key="$1" + value="$2" + var_type="${3:-string}" + start="(['\"])$(sed_escape_lhs "$key")\2\s*," + end="\);" + if [ "${key:0:1}" = '$' ]; then + start="^(\s*)$(sed_escape_lhs "$key")\s*=" + end=";" + fi + sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php + } + + set_config 'DB_HOST' "$WORDPRESS_DB_HOST" + set_config 'DB_USER' "$WORDPRESS_DB_USER" + set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" + set_config 'DB_NAME' "$WORDPRESS_DB_NAME" + set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" + set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" + + for unique in "${uniqueEnvs[@]}"; do + uniqVar="WORDPRESS_$unique" + if [ -n "${!uniqVar}" ]; then + set_config "$unique" "${!uniqVar}" + else + # if not specified, let's generate a random value + currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" + if [ "$currentVal" = 'put your unique phrase here' ]; then + set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" + fi + fi + done + + if [ "$WORDPRESS_TABLE_PREFIX" ]; then + set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" + fi + + if [ "$WORDPRESS_DEBUG" ]; then + set_config 'WP_DEBUG' 1 boolean + fi + + if ! TERM=dumb php -- <<'EOPHP' +connect_error) { + fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); + --$maxTries; + if ($maxTries <= 0) { + exit(1); + } + sleep(3); + } +} while ($mysql->connect_error); + +if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { + fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); + $mysql->close(); + exit(1); +} + +$mysql->close(); +EOPHP + then + echo >&2 + echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" + echo >&2 ' continuing anyways (which might have unexpected results)' + echo >&2 + fi + fi + + # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) + for e in "${envs[@]}"; do + unset "$e" + done +fi + +exec "$@" diff --git a/php7.4/fpm-alpine/docker-entrypoint.sh b/php7.4/fpm-alpine/docker-entrypoint.sh deleted file mode 100755 index 8878d3e919..0000000000 --- a/php7.4/fpm-alpine/docker-entrypoint.sh +++ /dev/null @@ -1,301 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - echo >&2 "error: both $var and $fileVar are set (but are exclusive)" - exit 1 - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then - if [ "$(id -u)" = '0' ]; then - case "$1" in - apache2*) - user="${APACHE_RUN_USER:-www-data}" - group="${APACHE_RUN_GROUP:-www-data}" - - # strip off any '#' symbol ('#1000' is valid syntax for Apache) - pound='#' - user="${user#$pound}" - group="${group#$pound}" - ;; - *) # php-fpm - user='www-data' - group='www-data' - ;; - esac - else - user="$(id -u)" - group="$(id -g)" - fi - - if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then - # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) - if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then - chown "$user:$group" . - fi - - echo >&2 "WordPress not found in $PWD - copying now..." - if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then - echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" - fi - sourceTarArgs=( - --create - --file - - --directory /usr/src/wordpress - --owner "$user" --group "$group" - ) - targetTarArgs=( - --extract - --file - - ) - if [ "$user" != '0' ]; then - # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" - targetTarArgs+=( --no-overwrite-dir ) - fi - # loop over "pluggable" content in the source, and if it already exists in the destination, skip it - # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) - for contentDir in /usr/src/wordpress/wp-content/*/*/; do - contentDir="${contentDir%/}" - [ -d "$contentDir" ] || continue - contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. - if [ -d "$PWD/$contentPath" ]; then - echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" - sourceTarArgs+=( --exclude "./$contentPath" ) - fi - done - tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" - echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi - fi - - # allow any of these "Authentication Unique Keys and Salts." to be specified via - # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") - uniqueEnvs=( - AUTH_KEY - SECURE_AUTH_KEY - LOGGED_IN_KEY - NONCE_KEY - AUTH_SALT - SECURE_AUTH_SALT - LOGGED_IN_SALT - NONCE_SALT - ) - envs=( - WORDPRESS_DB_HOST - WORDPRESS_DB_USER - WORDPRESS_DB_PASSWORD - WORDPRESS_DB_NAME - WORDPRESS_DB_CHARSET - WORDPRESS_DB_COLLATE - "${uniqueEnvs[@]/#/WORDPRESS_}" - WORDPRESS_TABLE_PREFIX - WORDPRESS_DEBUG - WORDPRESS_CONFIG_EXTRA - ) - haveConfig= - for e in "${envs[@]}"; do - file_env "$e" - if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then - haveConfig=1 - fi - done - - # linking backwards-compatibility - if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then - haveConfig=1 - # host defaults to "mysql" below if unspecified - : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" - if [ "$WORDPRESS_DB_USER" = 'root' ]; then - : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" - else - : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" - fi - : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" - fi - - # only touch "wp-config.php" if we have environment-supplied configuration values - if [ "$haveConfig" ]; then - : "${WORDPRESS_DB_HOST:=mysql}" - : "${WORDPRESS_DB_USER:=root}" - : "${WORDPRESS_DB_PASSWORD:=}" - : "${WORDPRESS_DB_NAME:=wordpress}" - : "${WORDPRESS_DB_CHARSET:=utf8}" - : "${WORDPRESS_DB_COLLATE:=}" - - # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks - # https://github.com/docker-library/wordpress/issues/116 - # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 - sed -ri -e 's/\r$//' wp-config* - - if [ ! -e wp-config.php ]; then - awk ' - /^\/\*.*stop editing.*\*\/$/ && c == 0 { - c = 1 - system("cat") - if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { - print "// WORDPRESS_CONFIG_EXTRA" - print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" - } - } - { print } - ' wp-config-sample.php > wp-config.php <<'EOPHP' -// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact -// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy -if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - $_SERVER['HTTPS'] = 'on'; -} - -EOPHP - chown "$user:$group" wp-config.php - elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then - # (if the config file already contains the requested PHP code, don't print a warning) - echo >&2 - echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' - echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' - echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' - echo >&2 - fi - - # see http://stackoverflow.com/a/2705678/433558 - sed_escape_lhs() { - echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' - } - sed_escape_rhs() { - echo "$@" | sed -e 's/[\/&]/\\&/g' - } - php_escape() { - local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" - if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then - escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" - fi - echo "$escaped" - } - set_config() { - key="$1" - value="$2" - var_type="${3:-string}" - start="(['\"])$(sed_escape_lhs "$key")\2\s*," - end="\);" - if [ "${key:0:1}" = '$' ]; then - start="^(\s*)$(sed_escape_lhs "$key")\s*=" - end=";" - fi - sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php - } - - set_config 'DB_HOST' "$WORDPRESS_DB_HOST" - set_config 'DB_USER' "$WORDPRESS_DB_USER" - set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" - set_config 'DB_NAME' "$WORDPRESS_DB_NAME" - set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" - set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" - - for unique in "${uniqueEnvs[@]}"; do - uniqVar="WORDPRESS_$unique" - if [ -n "${!uniqVar}" ]; then - set_config "$unique" "${!uniqVar}" - else - # if not specified, let's generate a random value - currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" - if [ "$currentVal" = 'put your unique phrase here' ]; then - set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" - fi - fi - done - - if [ "$WORDPRESS_TABLE_PREFIX" ]; then - set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" - fi - - if [ "$WORDPRESS_DEBUG" ]; then - set_config 'WP_DEBUG' 1 boolean - fi - - if ! TERM=dumb php -- <<'EOPHP' -connect_error) { - fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); - --$maxTries; - if ($maxTries <= 0) { - exit(1); - } - sleep(3); - } -} while ($mysql->connect_error); - -if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { - fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); - $mysql->close(); - exit(1); -} - -$mysql->close(); -EOPHP - then - echo >&2 - echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" - echo >&2 ' continuing anyways (which might have unexpected results)' - echo >&2 - fi - fi - - # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) - for e in "${envs[@]}"; do - unset "$e" - done -fi - -exec "$@" diff --git a/php7.4/fpm/docker-entrypoint.sh b/php7.4/fpm/docker-entrypoint.sh deleted file mode 100755 index 8878d3e919..0000000000 --- a/php7.4/fpm/docker-entrypoint.sh +++ /dev/null @@ -1,301 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - echo >&2 "error: both $var and $fileVar are set (but are exclusive)" - exit 1 - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then - if [ "$(id -u)" = '0' ]; then - case "$1" in - apache2*) - user="${APACHE_RUN_USER:-www-data}" - group="${APACHE_RUN_GROUP:-www-data}" - - # strip off any '#' symbol ('#1000' is valid syntax for Apache) - pound='#' - user="${user#$pound}" - group="${group#$pound}" - ;; - *) # php-fpm - user='www-data' - group='www-data' - ;; - esac - else - user="$(id -u)" - group="$(id -g)" - fi - - if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then - # if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory) - if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then - chown "$user:$group" . - fi - - echo >&2 "WordPress not found in $PWD - copying now..." - if [ -n "$(find -mindepth 1 -maxdepth 1 -not -name wp-content)" ]; then - echo >&2 "WARNING: $PWD is not empty! (copying anyhow)" - fi - sourceTarArgs=( - --create - --file - - --directory /usr/src/wordpress - --owner "$user" --group "$group" - ) - targetTarArgs=( - --extract - --file - - ) - if [ "$user" != '0' ]; then - # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" - targetTarArgs+=( --no-overwrite-dir ) - fi - # loop over "pluggable" content in the source, and if it already exists in the destination, skip it - # https://github.com/docker-library/wordpress/issues/506 ("wp-content" persisted, "akismet" updated, WordPress container restarted/recreated, "akismet" downgraded) - for contentDir in /usr/src/wordpress/wp-content/*/*/; do - contentDir="${contentDir%/}" - [ -d "$contentDir" ] || continue - contentPath="${contentDir#/usr/src/wordpress/}" # "wp-content/plugins/akismet", etc. - if [ -d "$PWD/$contentPath" ]; then - echo >&2 "WARNING: '$PWD/$contentPath' exists! (not copying the WordPress version)" - sourceTarArgs+=( --exclude "./$contentPath" ) - fi - done - tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}" - echo >&2 "Complete! WordPress has been successfully copied to $PWD" - if [ ! -e .htaccess ]; then - # NOTE: The "Indexes" option is disabled in the php:apache base image - cat > .htaccess <<-'EOF' - # BEGIN WordPress - - RewriteEngine On - RewriteBase / - RewriteRule ^index\.php$ - [L] - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /index.php [L] - - # END WordPress - EOF - chown "$user:$group" .htaccess - fi - fi - - # allow any of these "Authentication Unique Keys and Salts." to be specified via - # environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY") - uniqueEnvs=( - AUTH_KEY - SECURE_AUTH_KEY - LOGGED_IN_KEY - NONCE_KEY - AUTH_SALT - SECURE_AUTH_SALT - LOGGED_IN_SALT - NONCE_SALT - ) - envs=( - WORDPRESS_DB_HOST - WORDPRESS_DB_USER - WORDPRESS_DB_PASSWORD - WORDPRESS_DB_NAME - WORDPRESS_DB_CHARSET - WORDPRESS_DB_COLLATE - "${uniqueEnvs[@]/#/WORDPRESS_}" - WORDPRESS_TABLE_PREFIX - WORDPRESS_DEBUG - WORDPRESS_CONFIG_EXTRA - ) - haveConfig= - for e in "${envs[@]}"; do - file_env "$e" - if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then - haveConfig=1 - fi - done - - # linking backwards-compatibility - if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then - haveConfig=1 - # host defaults to "mysql" below if unspecified - : "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}" - if [ "$WORDPRESS_DB_USER" = 'root' ]; then - : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}" - else - : "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}" - fi - : "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}" - fi - - # only touch "wp-config.php" if we have environment-supplied configuration values - if [ "$haveConfig" ]; then - : "${WORDPRESS_DB_HOST:=mysql}" - : "${WORDPRESS_DB_USER:=root}" - : "${WORDPRESS_DB_PASSWORD:=}" - : "${WORDPRESS_DB_NAME:=wordpress}" - : "${WORDPRESS_DB_CHARSET:=utf8}" - : "${WORDPRESS_DB_COLLATE:=}" - - # version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks - # https://github.com/docker-library/wordpress/issues/116 - # https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4 - sed -ri -e 's/\r$//' wp-config* - - if [ ! -e wp-config.php ]; then - awk ' - /^\/\*.*stop editing.*\*\/$/ && c == 0 { - c = 1 - system("cat") - if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) { - print "// WORDPRESS_CONFIG_EXTRA" - print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n" - } - } - { print } - ' wp-config-sample.php > wp-config.php <<'EOPHP' -// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact -// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy -if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - $_SERVER['HTTPS'] = 'on'; -} - -EOPHP - chown "$user:$group" wp-config.php - elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then - # (if the config file already contains the requested PHP code, don't print a warning) - echo >&2 - echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists' - echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.' - echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)' - echo >&2 - fi - - # see http://stackoverflow.com/a/2705678/433558 - sed_escape_lhs() { - echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g' - } - sed_escape_rhs() { - echo "$@" | sed -e 's/[\/&]/\\&/g' - } - php_escape() { - local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")" - if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then - escaped="${escaped//$'\n'/"' + \"\\n\" + '"}" - fi - echo "$escaped" - } - set_config() { - key="$1" - value="$2" - var_type="${3:-string}" - start="(['\"])$(sed_escape_lhs "$key")\2\s*," - end="\);" - if [ "${key:0:1}" = '$' ]; then - start="^(\s*)$(sed_escape_lhs "$key")\s*=" - end=";" - fi - sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php - } - - set_config 'DB_HOST' "$WORDPRESS_DB_HOST" - set_config 'DB_USER' "$WORDPRESS_DB_USER" - set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD" - set_config 'DB_NAME' "$WORDPRESS_DB_NAME" - set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET" - set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE" - - for unique in "${uniqueEnvs[@]}"; do - uniqVar="WORDPRESS_$unique" - if [ -n "${!uniqVar}" ]; then - set_config "$unique" "${!uniqVar}" - else - # if not specified, let's generate a random value - currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)" - if [ "$currentVal" = 'put your unique phrase here' ]; then - set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)" - fi - fi - done - - if [ "$WORDPRESS_TABLE_PREFIX" ]; then - set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX" - fi - - if [ "$WORDPRESS_DEBUG" ]; then - set_config 'WP_DEBUG' 1 boolean - fi - - if ! TERM=dumb php -- <<'EOPHP' -connect_error) { - fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n"); - --$maxTries; - if ($maxTries <= 0) { - exit(1); - } - sleep(3); - } -} while ($mysql->connect_error); - -if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) { - fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n"); - $mysql->close(); - exit(1); -} - -$mysql->close(); -EOPHP - then - echo >&2 - echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'" - echo >&2 ' continuing anyways (which might have unexpected results)' - echo >&2 - fi - fi - - # now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code) - for e in "${envs[@]}"; do - unset "$e" - done -fi - -exec "$@" diff --git a/update.sh b/update.sh index 4024c6002c..bac2d7581c 100755 --- a/update.sh +++ b/update.sh @@ -1,95 +1,7 @@ -#!/bin/bash -set -euo pipefail +#!/usr/bin/env bash +set -Eeuo pipefail cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" -phpVersions=( "$@" ) -if [ ${#phpVersions[@]} -eq 0 ]; then - phpVersions=( php*.*/ ) -fi -phpVersions=( "${phpVersions[@]%/}" ) - -current="$(curl -fsSL 'https://api.wordpress.org/core/version-check/1.7/' | jq -r '.offers[0].current')" -sha1="$(curl -fsSL "https://wordpress.org/wordpress-$current.tar.gz.sha1")" - -cliPossibleVersions=( $( - git ls-remote --tags 'https://github.com/wp-cli/wp-cli.git' \ - | sed -r 's!^[^\t]+\trefs/tags/v([^^]+).*!\1!g' \ - | sort --version-sort --reverse - ) -) -cliVersion= -cliSha512= -for cliPosVer in "${cliPossibleVersions[@]}"; do - cliUrl="https://github.com/wp-cli/wp-cli/releases/download/v${cliPosVer}/wp-cli-${cliPosVer}.phar.sha512" - if cliSha512="$(curl -fsSL "$cliUrl" 2>/dev/null)"; then - cliVersion="$cliPosVer" - break - fi -done -echo "$current (CLI '$cliVersion')" -# make sure we get a cliVersion -[ -n "$cliVersion" ] - -declare -A variantExtras=( - [apache]="$(< apache-extras.template)" -) -declare -A variantCmds=( - [apache]='apache2-foreground' - [fpm]='php-fpm' - [fpm-alpine]='php-fpm' - [cli]='' # unused -) -declare -A variantBases=( - [apache]='debian' - [fpm]='debian' - [fpm-alpine]='alpine' - [cli]='cli' -) - -sed_escape_rhs() { - sed -e 's/[\/&]/\\&/g; $!a\'$'\n''\\n' <<<"$*" | tr -d '\n' -} - -for phpVersion in "${phpVersions[@]}"; do - phpVersionDir="$phpVersion" - phpVersion="${phpVersion#php}" - - for variant in apache fpm fpm-alpine cli; do - dir="$phpVersionDir/$variant" - mkdir -p "$dir" - - extras="${variantExtras[$variant]:-}" - if [ -n "$extras" ]; then - extras=$'\n'"$extras"$'\n' - fi - cmd="${variantCmds[$variant]}" - base="${variantBases[$variant]}" - - entrypoint='docker-entrypoint.sh' - if [ "$variant" = 'cli' ]; then - entrypoint='cli-entrypoint.sh' - fi - - sed -r \ - -e 's!%%WORDPRESS_VERSION%%!'"$current"'!g' \ - -e 's!%%WORDPRESS_SHA1%%!'"$sha1"'!g' \ - -e 's!%%PHP_VERSION%%!'"$phpVersion"'!g' \ - -e 's!%%VARIANT%%!'"$variant"'!g' \ - -e 's!%%WORDPRESS_CLI_VERSION%%!'"$cliVersion"'!g' \ - -e 's!%%WORDPRESS_CLI_SHA512%%!'"$cliSha512"'!g' \ - -e 's!%%VARIANT_EXTRAS%%!'"$(sed_escape_rhs "$extras")"'!g' \ - -e 's!%%CMD%%!'"$cmd"'!g' \ - "Dockerfile-${base}.template" > "$dir/Dockerfile" - - case "$phpVersion" in - 7.3) - sed -ri \ - -e 's!gd --with-freetype --with-jpeg!gd --with-freetype-dir=/usr --with-jpeg-dir=/usr --with-png-dir=/usr!g' \ - "$dir/Dockerfile" - ;; - esac - - cp -a "$entrypoint" "$dir/docker-entrypoint.sh" - done -done +./versions.sh "$@" +./apply-templates.sh "$@" diff --git a/versions.json b/versions.json new file mode 100644 index 0000000000..45eb50f5c3 --- /dev/null +++ b/versions.json @@ -0,0 +1,41 @@ +{ + "beta": { + "phpVersions": [ + "7.4", + "7.3" + ], + "sha1": "db8b75bfc9de27490434b365c12fd805ca6784ce", + "upstream": "5.6", + "variants": [ + "apache", + "fpm", + "fpm-alpine" + ], + "version": "5.6.0" + }, + "cli": { + "phpVersions": [ + "7.4", + "7.3" + ], + "sha512": "4049c7e45e14276a70a41c3b0864be7a6a8cfa8ea65ebac8b184a4f503a91baa1a0d29260d03248bc74aef70729824330fb6b396336172a624332e16f64e37ef", + "variants": [ + "alpine" + ], + "version": "2.4.0" + }, + "latest": { + "phpVersions": [ + "7.4", + "7.3" + ], + "sha1": "db8b75bfc9de27490434b365c12fd805ca6784ce", + "upstream": "5.6", + "variants": [ + "apache", + "fpm", + "fpm-alpine" + ], + "version": "5.6.0" + } +} diff --git a/versions.sh b/versions.sh new file mode 100755 index 0000000000..77631c6d88 --- /dev/null +++ b/versions.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" + +versions=( "$@" ) +if [ "${#versions[@]}" -eq 0 ]; then + versions=( */ ) + json='{}' +else + json="$(< versions.json)" +fi +versions=( "${versions[@]%/}" ) + +for version in "${versions[@]}"; do + export version + + doc='{}' + + fullVersion= + if [ "$version" = 'cli' ]; then + possibleVersions=( $( + git ls-remote --tags 'https://github.com/wp-cli/wp-cli.git' \ + | sed -r 's!^[^\t]+\trefs/tags/v([^^]+).*$!\1!g' \ + | sort --version-sort --reverse + ) ) + for possibleVersion in "${possibleVersions[@]}"; do + url="https://github.com/wp-cli/wp-cli/releases/download/v${possibleVersion}/wp-cli-${possibleVersion}.phar.sha512" + if sha512="$(wget -qO- "$url" 2>/dev/null)" && [ -n "$sha512" ]; then + export sha512 + doc="$(jq <<<"$doc" -c '.sha512 = env.sha512')" + fullVersion="$possibleVersion" + break + fi + done + else + possibleVersion="$( + wget -qO- "https://api.wordpress.org/core/version-check/1.7/?channel=$version" \ + | jq -r '.offers[0].current' + )" + if [ -n "$possibleVersion" ] && sha1="$(wget -qO- "https://wordpress.org/wordpress-$possibleVersion.tar.gz.sha1")" && [ -n "$sha1" ]; then + fullVersion="$possibleVersion" + export sha1 fullVersion + doc="$(jq <<<"$doc" -c '.sha1 = env.sha1 | .upstream = env.fullVersion')" + if [[ "$fullVersion" != *.*.* && "$fullVersion" == *.* && "$fullVersion" != *-* ]]; then + fullVersion+='.0' + fi + fi + fi + if [ -z "$fullVersion" ]; then + echo >&2 "error: failed to find version for $version" + exit 1 + fi + echo "$version: $fullVersion" + + export fullVersion + json="$( + jq <<<"$json" -c --argjson doc "$doc" ' + .[env.version] = { + version: env.fullVersion, + phpVersions: [ "7.4", "7.3" ], + variants: ( + if env.version == "cli" then + [ "alpine" ] + else + [ "apache", "fpm", "fpm-alpine" ] + end + ), + } + $doc + ' + )" +done + +jq <<<"$json" -S . > versions.json