From d9d8e5fc34df7ea526aa062eec961281d0fbb9a6 Mon Sep 17 00:00:00 2001 From: Michele Locati Date: Wed, 11 Apr 2018 17:39:10 +0200 Subject: [PATCH] Initial commit --- README.md | 107 +++++++++ data/special-requirements | 1 + data/supported-extensions | 55 +++++ install-php-extensions | 481 ++++++++++++++++++++++++++++++++++++++ scripts/common | 28 +++ scripts/update-readme | 242 +++++++++++++++++++ 6 files changed, 914 insertions(+) create mode 100644 README.md create mode 100644 data/special-requirements create mode 100644 data/supported-extensions create mode 100755 install-php-extensions create mode 100755 scripts/common create mode 100755 scripts/update-readme diff --git a/README.md b/README.md new file mode 100644 index 0000000..33335a3 --- /dev/null +++ b/README.md @@ -0,0 +1,107 @@ +# Easy installation of PHP extensions in official PHP Docker images + +This repository contains a script that can be used to easily install a PHP extension inside the [official PHP Docker images](https://hub.docker.com/_/php/). + +## Known limits + +Currently the script requires the Debian-based images (no Alpine). + + +## Usage + +Here's a sample Dockerfile that installs the GD and xdedub extensions inside a docker image: + +``` +FROM php:7.2-cli + +ADD https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions /usr/local/bin/ + +RUN install-php-extensions gd xdebug +``` + +## Supported PHP extensions + + + + + + + + + +| Extension | PHP 5.6 | PHP 7.0 | PHP 7.1 | PHP 7.2 | +|:---:|:---:|:---:|:---:|:---:| +| apcu | | V | V | V | +| bcmath | V | V | V | V | +| bz2 | V | V | V | V | +| calendar | V | V | V | V | +| cmark | | V | V | V | +| dba | V | V | V | V | +| enchant | V | V | V | V | +| exif | V | V | V | V | +| gd | V | V | V | V | +| gettext | V | V | V | V | +| gmp | V | V | V | V | +| imagick | V | V | V | V | +| imap | V | V | V | V | +| interbase | V | V | V | V | +| intl | V | V | V | V | +| ldap | V | V | V | V | +| mcrypt | V | V | V | | +| memcache | V | | | | +| memcached | V | V | V | V | +| mysql | V | | | | +| mysqli | V | V | V | V | +| odbc | V | V | V | V | +| opcache | V | V | V | V | +| pcntl | V | V | V | V | +| pdo_dblib | V | V | V | V | +| pdo_firebird | V | V | V | V | +| pdo_mysql | V | V | V | V | +| pdo_odbc | V | V | V | V | +| pdo_pgsql | V | V | V | V | +| pdo_sqlsrv | | V | V | V | +| pgsql | V | V | V | V | +| pspell | V | V | V | V | +| pthreads | V | V | | | +| recode | V | V | V | V | +| redis | V | V | V | V | +| shmop | V | V | V | V | +| snmp | V | V | V | V | +| soap | V | V | V | V | +| sockets | V | V | V | V | +| solr | V | V | V | | +| sqlsrv | | V | V | V | +| ssh2 | V | V | V | V | +| sybase_ct | V | | | | +| sysvmsg | V | V | V | V | +| sysvsem | V | V | V | V | +| sysvshm | V | V | V | V | +| tidy | V | V | V | V | +| timezonedb | V | V | V | V | +| uuid | V | V | V | V | +| wddx | V | V | V | V | +| xdebug | V | V | V | V | +| xmlrpc | V | V | V | V | +| xsl | V | V | V | V | +| yaml | V | V | V | V | +| zip | V | V | V | V | + + + +## Special requirements + +Some extension has special requirements: + + + + + + + + + +| Extension | Requirements | +|:---:|:---:| +| pthreads | Requires images with PHP compiled with thread-safety enabled (`zts`). | + diff --git a/data/special-requirements b/data/special-requirements new file mode 100644 index 0000000..b3fc69e --- /dev/null +++ b/data/special-requirements @@ -0,0 +1 @@ +pthreads zts \ No newline at end of file diff --git a/data/supported-extensions b/data/supported-extensions new file mode 100644 index 0000000..5845a78 --- /dev/null +++ b/data/supported-extensions @@ -0,0 +1,55 @@ +apcu 7.0 7.1 7.2 +bcmath 5.6 7.0 7.1 7.2 +bz2 5.6 7.0 7.1 7.2 +calendar 5.6 7.0 7.1 7.2 +cmark 7.0 7.1 7.2 +dba 5.6 7.0 7.1 7.2 +enchant 5.6 7.0 7.1 7.2 +exif 5.6 7.0 7.1 7.2 +gd 5.6 7.0 7.1 7.2 +gettext 5.6 7.0 7.1 7.2 +gmp 5.6 7.0 7.1 7.2 +imagick 5.6 7.0 7.1 7.2 +imap 5.6 7.0 7.1 7.2 +interbase 5.6 7.0 7.1 7.2 +intl 5.6 7.0 7.1 7.2 +ldap 5.6 7.0 7.1 7.2 +mcrypt 5.6 7.0 7.1 +memcache 5.6 +memcached 5.6 7.0 7.1 7.2 +mysql 5.6 +mysqli 5.6 7.0 7.1 7.2 +odbc 5.6 7.0 7.1 7.2 +opcache 5.6 7.0 7.1 7.2 +pcntl 5.6 7.0 7.1 7.2 +pdo_dblib 5.6 7.0 7.1 7.2 +pdo_firebird 5.6 7.0 7.1 7.2 +pdo_mysql 5.6 7.0 7.1 7.2 +pdo_odbc 5.6 7.0 7.1 7.2 +pdo_pgsql 5.6 7.0 7.1 7.2 +pdo_sqlsrv 7.0 7.1 7.2 +pgsql 5.6 7.0 7.1 7.2 +pspell 5.6 7.0 7.1 7.2 +pthreads 5.6 7.0 +recode 5.6 7.0 7.1 7.2 +redis 5.6 7.0 7.1 7.2 +shmop 5.6 7.0 7.1 7.2 +snmp 5.6 7.0 7.1 7.2 +soap 5.6 7.0 7.1 7.2 +sockets 5.6 7.0 7.1 7.2 +solr 5.6 7.0 7.1 +sqlsrv 7.0 7.1 7.2 +ssh2 5.6 7.0 7.1 7.2 +sybase_ct 5.6 +sysvmsg 5.6 7.0 7.1 7.2 +sysvsem 5.6 7.0 7.1 7.2 +sysvshm 5.6 7.0 7.1 7.2 +tidy 5.6 7.0 7.1 7.2 +timezonedb 5.6 7.0 7.1 7.2 +uuid 5.6 7.0 7.1 7.2 +wddx 5.6 7.0 7.1 7.2 +xdebug 5.6 7.0 7.1 7.2 +xmlrpc 5.6 7.0 7.1 7.2 +xsl 5.6 7.0 7.1 7.2 +yaml 5.6 7.0 7.1 7.2 +zip 5.6 7.0 7.1 7.2 diff --git a/install-php-extensions b/install-php-extensions new file mode 100755 index 0000000..42a17ad --- /dev/null +++ b/install-php-extensions @@ -0,0 +1,481 @@ +#!/bin/sh + +# This script wraps docker-php-ext-install, properly configuring the system. +# +# Copyright (c) Michele Locati, 2018 +# +# MIT license + +# Let's set a sane environment +set -o errexit +set -o nounset + +# Reset the Internal Field Separator +resetIFS () { + IFS=' +' +} + +# Get the PHP Major-Minor version as an integer value, in format MMmm (example: 506 for PHP 5.6.15) +# +# Output: +# The PHP numeric Major-Minor version +getPHPMajorMinor () { + php -r '$v = explode(".", PHP_VERSION); echo $v[0] * 100 + $v[1];' +} + +# Get the normalized list of already installed PHP modules +# +# Output: +# Space-separated list of module handles +getPHPInstalledModules () { + getPHPInstalledModules_result='' + IFS=' +' + for getPHPInstalledModules_module in $(php -m) + do + getPHPInstalledModules_moduleNormalized='' + case "${getPHPInstalledModules_module}" in + \[PHP\ Modules\]) + ;; + \[Zend\ Modules\]) + break + ;; + Core|PDO|PDO_*|Phar|Reflection|SimpleXML|SPL|SQLite|Xdebug) + getPHPInstalledModules_moduleNormalized=$(LC_CTYPE=C printf '%s' "${getPHPInstalledModules_module}" | tr '[:upper:]' '[:lower:]') + ;; + Zend\ OPcache) + getPHPInstalledModules_moduleNormalized='opcache' + ;; + *\ *|A*|*B*|*C*|*D*|*E*|*F*|*G*|*H*|*I*|*J*|*K*|*L*|*M*|*N*|*O*|*P*|*Q*|*R*|*S*|*T*|*U*|*V*|*W*|*X*|*Y*|*Z*) + printf '### WARNING Unrecognized module name: %s ###\n' "${getPHPInstalledModules_module}" >&2 + ;; + *) + getPHPInstalledModules_moduleNormalized="${getPHPInstalledModules_module}" + ;; + esac + if test -n "${getPHPInstalledModules_moduleNormalized}" + then + if ! stringInList "${getPHPInstalledModules_moduleNormalized}" "${getPHPInstalledModules_result}" + then + getPHPInstalledModules_result="${getPHPInstalledModules_result} ${getPHPInstalledModules_moduleNormalized}" + fi + fi + done + resetIFS + printf '%s' "${getPHPInstalledModules_result}" +} + +# Get the handles of the modules to be installed +# +# Arguments: +# $@: all module handles +# Output: +# Space-separated list of module handles +getModulesToInstall () { + getModulesToInstall_alreadyInstalled="$(getPHPInstalledModules)" + getModulesToInstall_result='' + while : + do + if test $# -lt 1 + then + break + fi + if stringInList "${1}" "${getModulesToInstall_result}" + then + printf '### WARNING Duplicated module name specified: %s ###\n' "${1}" >&2 + elif stringInList "${1}" "${getModulesToInstall_alreadyInstalled}" + then + printf '### WARNING Module already installed: %s ###\n' "${1}" >&2 + else + getModulesToInstall_result="${getModulesToInstall_result} ${1}" + fi + shift + done + printf '%s' "${getModulesToInstall_result}" +} + +# Get the required APT packages for a specific PHP version and for the list of module handles +# +# Arguments: +# $1: the numeric PHP Major-Minor version +# $@: the PHP module handles +# +# Output: +# Space-separated list of APT packages +getRequiredAptPackages () { + getRequiredAptPackages_result='' + getRequiredAptPackages_phpv=${1} + while : + do + if test $# -lt 2 + then + break + fi + shift + case "${1}" in + bz2) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libbz2-dev" + ;; + cmark) + getRequiredAptPackages_result="${getRequiredAptPackages_result} cmake" + ;; + enchant) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libenchant-dev" + ;; + gd) + if test $getRequiredAptPackages_phpv -lt 700 + then + getRequiredAptPackages_result="${getRequiredAptPackages_result} libvpx-dev libjpeg62-turbo-dev libpng-dev libxpm-dev libfreetype6-dev" + else + getRequiredAptPackages_result="${getRequiredAptPackages_result} libwebp-dev libjpeg62-turbo-dev libpng-dev libxpm-dev libfreetype6-dev" + fi + ;; + gmp) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libgmp-dev" + ;; + imap) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libc-client-dev libkrb5-dev" + ;; + interbase) + getRequiredAptPackages_result="${getRequiredAptPackages_result} firebird-dev libib-util" + ;; + imagick) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libmagickwand-dev" + ;; + intl) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libicu-dev" + ;; + ldap) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libldap2-dev" + ;; + memcache) + getRequiredAptPackages_result="${getRequiredAptPackages_result} zlib1g-dev" + ;; + memcached) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libmemcached-dev zlib1g-dev" + ;; + mcrypt) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libmcrypt-dev" + ;; + mssql) + getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + ;; + odbc) + getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + ;; + pdo_dblib) + getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + ;; + pdo_firebird) + getRequiredAptPackages_result="${getRequiredAptPackages_result} firebird-dev libib-util" + ;; + pdo_pgsql) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libpq-dev" + ;; + pdo_odbc) + getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + ;; + pdo_sqlsrv) + getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + ;; + pgsql) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libpq-dev" + ;; + pspell) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libpspell-dev" + ;; + recode) + getRequiredAptPackages_result="${getRequiredAptPackages_result} librecode-dev" + ;; + ssh2) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libssh2-1-dev" + ;; + snmp) + getRequiredAptPackages_result="${getRequiredAptPackages_result} snmp libsnmp-dev" + ;; + soap) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + ;; + solr) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libcurl4-gnutls-dev libxml2-dev" + ;; + sqlsrv) + getRequiredAptPackages_result="${getRequiredAptPackages_result} unixodbc-dev" + ;; + sybase_ct) + getRequiredAptPackages_result="${getRequiredAptPackages_result} freetds-dev" + ;; + tidy) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libtidy-dev" + ;; + uuid) + getRequiredAptPackages_result="${getRequiredAptPackages_result} uuid-dev" + ;; + wddx) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + ;; + xmlrpc) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libxml2-dev" + ;; + xsl) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libxslt-dev" + ;; + yaml) + getRequiredAptPackages_result="${getRequiredAptPackages_result} libyaml-dev" + ;; + zip) + getRequiredAptPackages_result="${getRequiredAptPackages_result} zlib1g-dev" + ;; + esac + done + printf '%s' "${getRequiredAptPackages_result}" +} + +# Install a bundled PHP module given its handle +# +# Arguments: +# $1: the numeric PHP Major-Minor version +# $2: the handle of the PHP module +installBundledModule () { + printf '### INSTALLING BUNDLED MODULE %s ###\n' "${2}" + case "${2}" in + gd) + if test $1 -lt 700 + then + docker-php-ext-configure gd --with-gd --with-vpx-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf + elif test $1 -lt 702 + then + docker-php-ext-configure gd --with-gd --with-webp-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir --enable-gd-native-ttf + else + docker-php-ext-configure gd --with-gd --with-webp-dir --with-jpeg-dir --with-png-dir --with-zlib-dir --with-xpm-dir --with-freetype-dir + fi + ;; + gmp) + case "$1" in + 506) + if ! test -f /usr/include/gmp.h + then + ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h + fi + ;; + esac + ;; + imap) + docker-php-ext-configure imap --with-kerberos --with-imap-ssl + ;; + ldap) + docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu + ;; + mssql|pdo_dblib) + case "$1" in + 506|700|701|702) + if ! test -f /usr/lib/libsybdb.so + then + ln -s /usr/lib/x86_64-linux-gnu/libsybdb.so /usr/lib/libsybdb.so + fi + ;; + esac + ;; + odbc) + case "$1" in + 506|700|701|702) + docker-php-source extract + cd /usr/src/php/ext/odbc + phpize + sed -ri 's@^ *test +"\$PHP_.*" *= *"no" *&& *PHP_.*=yes *$@#&@g' configure + ./configure --with-unixODBC=shared,/usr + cd - + ;; + esac + ;; + pdo_odbc) + docker-php-ext-configure pdo_odbc --with-pdo-odbc=unixODBC,/usr + ;; + sybase_ct) + docker-php-ext-configure sybase_ct --with-sybase-ct=/usr + ;; + esac + docker-php-ext-install "${2}" +} + +# Fetch a tar.gz file, extract it and returns the path of the extracted folder. +# +# Arguments: +# $1: the URL of the file to be downloaded +# +# Output: +# The path of the extracted directory +getPackageSource () { + mkdir -p /tmp/src + getPackageSource_tempFile=$(mktemp -p /tmp/src) + curl -L -s -S -o "${getPackageSource_tempFile}" "$1" + getPackageSource_tempDir=$(mktemp -p /tmp/src -d) + cd "${getPackageSource_tempDir}" + tar -xzf "${getPackageSource_tempFile}" + cd - >/dev/null + unlink "${getPackageSource_tempFile}" + getPackageSource_outDir='' + for getPackageSource_i in $(ls "${getPackageSource_tempDir}") + do + if test -n "${getPackageSource_outDir}" -o -f "${getPackageSource_tempDir}/${getPackageSource_i}" + then + getPackageSource_outDir='' + break + fi + getPackageSource_outDir="${getPackageSource_tempDir}/${getPackageSource_i}" + done + if test -n "${getPackageSource_outDir}" + then + printf '%s' "${getPackageSource_outDir}" + else + printf '%s' "${getPackageSource_tempDir}" + fi +} + +# Install a PHP module given its handle from source code +# +# Arguments: +# $1: the handle of the PHP module +# $2: the URL of the module source code +# $3: the options of the configure command +installModuleFromSource () { + printf '### INSTALLING MODULE %s FROM SOURCE CODE ###\n' "${1}" + installModuleFromSource_dir="$(getPackageSource "${2}")" + cd "${installModuleFromSource_dir}" + phpize + ./configure ${3} + make -j$(nproc) install + cd -- + docker-php-ext-enable "${1}" +} + +# Install a PECL PHP module given its handle +# +# Arguments: +# $1: the numeric PHP Major-Minor version +# $2: the handle of the PHP module +installPECLModule () { + printf '### INSTALLING PECL MODULE %s ###\n' "${2}" + installPECLModule_actual="${2}" + case "${2}" in + memcached) + if test $1 -lt 700 + then + installPECLModule_actual="${2}-2.2.0" + fi + ;; + pthreads) + if test $1 -lt 700 + then + installPECLModule_actual="${2}-2.0.10" + fi + ;; + ssh2) + if test $1 -ge 700 + then + installPECLModule_actual="${2}-1.1.2" + fi + ;; + xdebug) + if test $1 -lt 501 + then + installPECLModule_actual="${2}-2.0.5" + elif test $1 -lt 504 + then + installPECLModule_actual="${2}-2.2.7" + elif test $1 -lt 505 + then + installPECLModule_actual="${2}-2.4.1" + elif test $1 -lt 700 + then + installPECLModule_actual="${2}-2.5.5" + fi + ;; + yaml) + if test $1 -lt 700 + then + installPECLModule_actual="${2}-1.3.1" + fi + ;; + esac + if test "${2}" != "${installPECLModule_actual}" + then + printf ' (installing version %s)\n' "${installPECLModule_actual}" + fi + pecl install "${installPECLModule_actual}" + docker-php-ext-enable "${2}" +} + +# Check if a string is in a list of space-separated string +# +# Arguments: +# $1: the string to be checked +# $2: the string list +# +# Return: +# 0 (true): if the string is in the list +# 1 (false): if the string is not in the list +stringInList () { + for stringInList_listItem in ${2} + do + if test "${1}" = "${stringInList_listItem}" + then + return 0 + fi + done + return 1 +} + +resetIFS +TEMPORARY_DIRS='' +PHP_MAJMIN_VERSION=$(getPHPMajorMinor) +case "${PHP_MAJMIN_VERSION}" in + 506|700|701|702) + ;; + *) + printf "### ERROR: Unsupported PHP version: %s.%s ###\n" $(( PHP_MAJMIN_VERSION / 100 )) $(( PHP_MAJMIN_VERSION % 100 )) +esac +PHP_MODULES_TO_INSTALL=$(getModulesToInstall "$@") +if test -n "${PHP_MODULES_TO_INSTALL}" +then + REQUIRED_APT_PACKAGES=$(getRequiredAptPackages ${PHP_MAJMIN_VERSION} ${PHP_MODULES_TO_INSTALL}) + if test -n "${REQUIRED_APT_PACKAGES}" + then + printf '### INSTALLING REQUIRED APT PACKAGES ###\n' + DEBIAN_FRONTEND=noninteractive apt-get update -y + DEBIAN_FRONTEND=noninteractive apt-get install -y ${REQUIRED_APT_PACKAGES} + fi + docker-php-source extract + BUNDLED_MODULES="$(find /usr/src/php/ext -mindepth 2 -maxdepth 2 -type f -name 'config.m4' | xargs -n1 dirname | xargs -n1 basename | xargs)" + for PHP_MODULE_TO_INSTALL in ${PHP_MODULES_TO_INSTALL} + do + if stringInList "${PHP_MODULE_TO_INSTALL}" "${BUNDLED_MODULES}" + then + installBundledModule ${PHP_MAJMIN_VERSION} "${PHP_MODULE_TO_INSTALL}" + else + MODULE_SOURCE='' + MODULE_SOURCE_CONFIGOPTIONS='' + case "${PHP_MODULE_TO_INSTALL}" in + cmark) + MODULE_SOURCE=https://github.com/krakjoe/cmark/archive/v1.0.0.tar.gz + cd "$(getPackageSource https://github.com/commonmark/cmark/archive/0.28.3.tar.gz)" + make install + cd - + MODULE_SOURCE_CONFIGOPTIONS=--with-cmark + ;; + esac + if test -n "${MODULE_SOURCE}" + then + installModuleFromSource "${PHP_MODULE_TO_INSTALL}" "${MODULE_SOURCE}" "${MODULE_SOURCE_CONFIGOPTIONS}" + else + installPECLModule ${PHP_MAJMIN_VERSION} "${PHP_MODULE_TO_INSTALL}" + fi + fi + done +fi + +docker-php-source delete +rm -rf /tmp/pear +rm -rf /var/lib/apt/lists/* +#rm -rf /tmp/src diff --git a/scripts/common b/scripts/common new file mode 100755 index 0000000..b19af4f --- /dev/null +++ b/scripts/common @@ -0,0 +1,28 @@ +#!/bin/sh + +# Reset the Internal Field Separator +resetIFS () { + IFS=' +' +} + +# Check if a string is in a list of space-separated string +# +# Arguments: +# $1: the string to be checked +# $2: the string list +# +# Return: +# 0 (true): if the string is in the list +# 1 (false): if the string is not in the list +stringInList () { + resetIFS + for stringInList_listItem in ${2} + do + if test "${1}" = "${stringInList_listItem}" + then + return 0 + fi + done + return 1 +} diff --git a/scripts/update-readme b/scripts/update-readme new file mode 100755 index 0000000..b201308 --- /dev/null +++ b/scripts/update-readme @@ -0,0 +1,242 @@ +#!/bin/sh + +set -o errexit +set -o nounset + +SCRIPTS_DIR="$(CDPATH= cd -- "$(dirname -- "${0}")" && pwd)" +ROOT_DIR="$(dirname -- "${SCRIPTS_DIR}")" +DATA_DIR="${ROOT_DIR}/data" + +. "${SCRIPTS_DIR}/common" + + +# Get the list of PHP extensions from the data file +# +# Arguments: +# $1: the path to the data file +# +# Output: +# the list of PHP extensions +getExtensionList () { + getExtensionList_extensions='' + IFS=' +' + for getExtensionList_line in $(cat -- "${1}" | sort) + do + getExtensionList_extension='' + IFS=' ' + for getExtensionList_chunk in ${getExtensionList_line} + do + if test -z "${getExtensionList_extensions}" + then + getExtensionList_extensions="${getExtensionList_chunk}" + else + getExtensionList_extensions="${getExtensionList_extensions} ${getExtensionList_chunk}" + fi + break + done + done + printf '%s' "${getExtensionList_extensions}" +} + + +# Get the list of PHP versions from the data file +# +# Arguments: +# $1: the path to the data file +# +# Output: +# the list of PHP versions +getVersionList () { + getVersionList_versions='' + IFS=' +' + for getVersionList_line in $(cat -- "${1}" | sort) + do + getVersionList_extension='' + IFS=' ' + for getVersionList_chunk in ${getVersionList_line} + do + if test -z "${getVersionList_extension}" + then + getVersionList_extension="${getVersionList_chunk}" + elif test -z "${getVersionList_versions}" + then + getVersionList_versions="${getVersionList_chunk}" + elif ! stringInList "${getVersionList_chunk}" "${getVersionList_versions}" + then + getVersionList_versions="${getVersionList_versions} ${getVersionList_chunk}" + fi + done + done + sortVersionList "${getVersionList_versions}" +} + + +# Sort the list of PHP versions +# +# Arguments: +# $1: the list of PHP versions +# +# Output: +# the sorted list of PHP versions +sortVersionList () { + sortVersionList_list='' + IFS=' +' + for sortVersionList_version in $(printf '%s' "${1}" | tr ' ' '\n' | sort -t '.' -k 1,1n -k 2,2n -k 3,3n) + do + if test -z "${sortVersionList_list}" + then + sortVersionList_list="${sortVersionList_version}" + else + sortVersionList_list="${sortVersionList_list} ${sortVersionList_version}" + fi + done + printf '%s' "${sortVersionList_list}" +} + + +# Generate the markdown table with the supported PHP extensions +# +# Arguments: +# $1: the path to the data file +# +# Output: +# the markdown table +generateExtensionsTable () { + generateExtensionsTable_data=$(cat "${1}") + generateExtensionsTable_extensions="$(getExtensionList "${1}")" + generateExtensionsTable_versions="$(getVersionList "${1}")" + printf '| Extension |' + IFS=' ' + for generateExtensionsTable_version in ${generateExtensionsTable_versions} + do + printf ' PHP %s |' "${generateExtensionsTable_version}" + done + printf '\n' + printf '|:---:|' + for generateExtensionsTable_version in ${generateExtensionsTable_versions} + do + printf -- ':---:|' + done + printf '\n' + IFS=' ' + for generateExtensionsTable_extension in ${generateExtensionsTable_extensions} + do + printf '| %s |' "${generateExtensionsTable_extension}" + IFS=' ' + for generateExtensionsTable_version in ${generateExtensionsTable_versions} + do + printf ' ' + generateExtensionsTable_versionOk='' + IFS=' +' + for generateExtensionsTable_dataLine in ${generateExtensionsTable_data} + do + if stringInList "${generateExtensionsTable_extension}" "${generateExtensionsTable_dataLine}" + then + if stringInList "${generateExtensionsTable_version}" "${generateExtensionsTable_dataLine}" + then + generateExtensionsTable_versionOk='y' + fi + break + fi + done + if test -n "${generateExtensionsTable_versionOk}" + then + printf 'V' + fi + printf ' |' + done + printf '\n' + done +} + + +# Generate the markdown table with the special requirements for the PHP extensions +# +# Arguments: +# $1: the path to the data file +# +# Output: +# the markdown table +generateSpecialRequirementsTable () { + generateSpecialRequirementsTable_started='' + IFS=' +' + for generateSpecialRequirementsTable_line in $(cat -- "${1}" | sort) + do + if test -z "${generateSpecialRequirementsTable_started}" + then + printf '| Extension | Requirements |\n' + printf '|:---:|:---:|\n' + fi + resetIFS + generateSpecialRequirementsTable_requirement="$(echo "${generateSpecialRequirementsTable_line}" | sed -E 's/^\s*\w+\s+//')" + case "${generateSpecialRequirementsTable_requirement}" in + zts) + generateSpecialRequirementsTable_requirement='Requires images with PHP compiled with thread-safety enabled (`zts`).' + ;; + esac + printf '| %s | %s |\n' \ + "$(echo "${generateSpecialRequirementsTable_line}" | awk '{print $1;}')" \ + "${generateSpecialRequirementsTable_requirement}" + done +} + + +# Generate the contents of README.md +# +# Arguments: +# $1: the path to the README file +# $2: the path to the extensions data file +# $3: the path to the special requirements data file +# +# Output: +# the markdown table +generateReadme () { + generateReadme_ph_ExtensionsStart='' + generateReadme_ph_ExtensionsEnd='' + generateReadme_ph_SpecialStart='' + generateReadme_ph_SpecialEnd='' + generateReadme_skip='' + while IFS= read -r generateReadme_line + do + if test "${generateReadme_line}" = "${generateReadme_ph_ExtensionsEnd}" -o "${generateReadme_line}" = "${generateReadme_ph_SpecialEnd}" + then + generateReadme_skip='' + fi + if test -z "${generateReadme_skip}" + then + printf '%s\n' "${generateReadme_line}" + fi + if test "${generateReadme_line}" = "${generateReadme_ph_ExtensionsStart}" + then + generateReadme_skip='y' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + generateExtensionsTable "${2}" + elif test "${generateReadme_line}" = "${generateReadme_ph_SpecialStart}" + then + generateReadme_skip='y' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + printf '\n' + generateSpecialRequirementsTable "${3}" + fi + done < "${1}" + printf '%s' "${generateReadme_line}" +} + +NEW_README="$(generateReadme "${ROOT_DIR}/README.md" "${DATA_DIR}/supported-extensions" "${DATA_DIR}/special-requirements")" +printf '%s\n' "${NEW_README}" > "${ROOT_DIR}/README.md"