Skip to content

Commit f86091f

Browse files
Adds a PHP feature (#22)
* add php * add test * fix test * add to workflow * fix test * fix bug * test composer Co-authored-by: Josh Spicer <joshspicer@github.com>
1 parent 4b05519 commit f86091f

5 files changed

Lines changed: 219 additions & 1 deletion

File tree

.github/workflows/test.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ jobs:
2727
"go",
2828
"gradle",
2929
"hugo",
30-
"java",
30+
"java",
31+
"php",
3132
"python jupyterlab", # Install 'python', then 'jupyterlab'
3233
"kubectl-helm-minikube",
3334
"maven",

src/php/feature.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"id": "php",
3+
"name": "PHP",
4+
"options": {
5+
"version": {
6+
"type": "string",
7+
"proposals": ["latest", "8.0.16"],
8+
"default": "latest",
9+
"description": "Select or enter a PHP version"
10+
},
11+
"installComposer": {
12+
"type": "boolean",
13+
"default": true,
14+
"description": "Install PHP Composer?"
15+
}
16+
},
17+
"extensions": [
18+
"xdebug.php-debug",
19+
"bmewburn.vscode-intelephense-client",
20+
"xdebug.php-pack",
21+
"devsense.phptools-vscode"
22+
],
23+
"containerEnv": {
24+
"PHP_PATH": "/usr/local/php",
25+
"PATH":"${PHP_PATH}:${PHP_PATH}/bin:${PATH}"
26+
},
27+
"install": {
28+
"app": "",
29+
"file": "install.sh"
30+
}
31+
}

src/php/install.sh

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/usr/bin/env bash
2+
#-------------------------------------------------------------------------------------------------------------
3+
# Copyright (c) Microsoft Corporation. All rights reserved.
4+
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
5+
#-------------------------------------------------------------------------------------------------------------
6+
#
7+
# Maintainer: The VS Code and Codespaces Teams
8+
#
9+
# Syntax: ./php-debian.sh [PHP version] [PHP_DIR] [Add Composer flag] [Non-root user] [Add rc files flag]
10+
11+
VERSION=${1:-"latest"}
12+
export PHP_DIR=${2:-"/usr/local/php"}
13+
INSTALL_COMPOSER=${3:-"true"}
14+
USERNAME=${4:-"automatic"}
15+
UPDATE_RC=${5:-"true"}
16+
17+
set -eux
18+
export DEBIAN_FRONTEND=noninteractive
19+
20+
if [ "$(id -u)" -ne 0 ]; then
21+
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
22+
exit 1
23+
fi
24+
25+
26+
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
27+
rm -f /etc/profile.d/00-restore-env.sh
28+
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
29+
chmod +x /etc/profile.d/00-restore-env.sh
30+
31+
# Determine the appropriate non-root user
32+
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
33+
USERNAME=""
34+
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
35+
for CURRENT_USER in ${POSSIBLE_USERS[@]}; do
36+
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
37+
USERNAME=${CURRENT_USER}
38+
break
39+
fi
40+
done
41+
if [ "${USERNAME}" = "" ]; then
42+
USERNAME=root
43+
fi
44+
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
45+
USERNAME=root
46+
fi
47+
48+
architecture="$(uname -m)"
49+
if [ "${architecture}" != "amd64" ] && [ "${architecture}" != "x86_64" ] && [ "${architecture}" != "arm64" ] && [ "${architecture}" != "aarch64" ]; then
50+
echo "(!) Architecture $architecture unsupported"
51+
exit 1
52+
fi
53+
54+
updaterc() {
55+
if [ "${UPDATE_RC}" = "true" ]; then
56+
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
57+
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
58+
echo -e "$1" >> /etc/bash.bashrc
59+
fi
60+
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
61+
echo -e "$1" >> /etc/zsh/zshrc
62+
fi
63+
fi
64+
}
65+
66+
# Checks if packages are installed and installs them if not
67+
check_packages() {
68+
if ! dpkg -s "$@" > /dev/null 2>&1; then
69+
apt-get update
70+
apt-get -y install --no-install-recommends "$@"
71+
fi
72+
}
73+
74+
# Figure out correct version of PHP
75+
find_version_from_git_tags() {
76+
local repository="https://github.com/php/php-src"
77+
local separator="."
78+
local escaped_separator=${separator//./\\.}
79+
local last_part="${escaped_separator}[0-9]+"
80+
local regex="\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
81+
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
82+
VERSION="$(echo "${version_list}" | head -n 1)"
83+
}
84+
85+
# Install PHP Composer
86+
addcomposer() {
87+
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
88+
HASH="$(wget -q -O - https://composer.github.io/installer.sig)"
89+
php -r "if (hash_file('sha384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
90+
php composer-setup.php
91+
php -r "unlink('composer-setup.php');"
92+
93+
mv composer.phar $PHP_DIR/composer
94+
updaterc "export PHP_DIR=${PHP_DIR}"
95+
}
96+
97+
# Install PHP if it's missing
98+
if ! php --version &> /dev/null ; then
99+
# Persistent / runtime dependencies
100+
RUNTIME_DEPS="wget ca-certificates git build-essential xz-utils"
101+
102+
# PHP dependencies
103+
PHP_DEPS="libssl-dev libcurl4-openssl-dev libedit-dev libsqlite3-dev libxml2-dev zlib1g-dev libsodium-dev libargon2-dev libonig-dev"
104+
105+
# Dependencies required for running "phpize"
106+
PHPIZE_DEPS="autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c"
107+
108+
# Install dependencies
109+
check_packages $RUNTIME_DEPS $PHP_DEPS $PHPIZE_DEPS
110+
111+
# Fetch latest version of PHP if needed
112+
if [ "${VERSION}" = "latest" ] || [ "${VERSION}" = "lts" ]; then
113+
find_version_from_git_tags
114+
fi
115+
116+
PHP_URL="https://www.php.net/distributions/php-${VERSION}.tar.gz"
117+
118+
PHP_INI_DIR="$PHP_DIR/ini"
119+
CONF_DIR="$PHP_INI_DIR/conf.d"
120+
mkdir -p $CONF_DIR;
121+
122+
PHP_EXT_DIR="$PHP_DIR/extensions"
123+
mkdir -p $PHP_EXT_DIR
124+
125+
PHP_SRC_DIR="/usr/src/php"
126+
mkdir -p $PHP_SRC_DIR
127+
cd $PHP_SRC_DIR
128+
wget -O php.tar.xz "$PHP_URL"
129+
130+
tar -xf $PHP_SRC_DIR/php.tar.xz -C "$PHP_SRC_DIR" --strip-components=1
131+
cd $PHP_SRC_DIR;
132+
133+
# PHP 7.4+, the pecl/pear installers are officially deprecated and are removed in PHP 8+
134+
# Thus, requiring an explicit "--with-pear"
135+
IFS="."
136+
read -a versions <<< "$VERSION"
137+
PHP_MAJOR_VERSION=${versions[0]}
138+
PHP_MINOR_VERSION=${versions[1]}
139+
140+
VERSION_CONFIG=""
141+
if (( $(($PHP_MAJOR_VERSION)) >= 8 )) || (( $(($PHP_MAJOR_VERSION)) == 7 && $(($PHP_MINOR_VERSION)) >= 4 )); then
142+
VERSION_CONFIG="--with-pear"
143+
fi
144+
145+
./configure --prefix="$PHP_DIR" --with-config-file-path="$PHP_INI_DIR" --with-config-file-scan-dir="$CONF_DIR" --enable-option-checking=fatal --with-curl --with-libedit --with-openssl --with-zlib --with-password-argon2 --with-sodium=shared "$VERSION_CONFIG" EXTENSION_DIR="$PHP_EXT_DIR";
146+
147+
make -j "$(nproc)"
148+
find -type f -name '*.a' -delete
149+
make install
150+
find $PHP_DIR -type f -executable -exec strip --strip-all '{}' + || true
151+
make clean
152+
153+
cp -v $PHP_SRC_DIR/php.ini-* "$PHP_INI_DIR/";
154+
cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
155+
PATH=$PATH:${PHP_DIR}/bin
156+
157+
# Install xdebug
158+
pecl install xdebug
159+
XDEBUG_INI="$CONF_DIR/xdebug.ini"
160+
echo "zend_extension=$(find PHP_EXT_DIR -name xdebug.so)" > XDEBUG_INI
161+
echo "xdebug.mode = debug" >> XDEBUG_INI
162+
echo "xdebug.start_with_request = yes" >> XDEBUG_INI
163+
echo "xdebug.client_port = 9003" >> XDEBUG_INI
164+
165+
# Install PHP Composer if needed
166+
if [ "${INSTALL_COMPOSER}" = "true" ]; then
167+
addcomposer
168+
fi
169+
170+
updaterc "export PHP_DIR=${PHP_DIR}/bin"
171+
fi
172+
173+
echo "Done!"

test/php/test.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Optional: Import test library
6+
source dev-container-features-test-lib
7+
8+
check "PHP version" php --version
9+
check "Composer version" composer --version
10+
11+
# Report result
12+
reportResults

v1/feature-scripts.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ _BUILD_ARG_POWERSHELL="./powershell/install.sh ${_B
2121
_BUILD_ARG_DESKTOP_LITE="./desktop-lite/install.sh automatic ${_BUILD_ARG_DESKTOP_LITE_PASSWORD:-vscode} true ${_BUILD_ARG_DESKTOP_LITE_VNCPORT:-5901} ${_BUILD_ARG_DESKTOP_LITE_WEBPORT:-6080}"
2222
_BUILD_ARG_DOTNET="./dotnet/install.sh ${_BUILD_ARG_DOTNET_VERSION:-latest} ${_BUILD_ARG_DOTNET_RUNTIMEONLY:-false} automatic true /usr/local/dotnet dotnet"
2323
_BUILD_ARG_JUPYTERLAB="./jupyterlab/install.sh ${_BUILD_ARG_JUPYTERLAB_VERSION:-latest}" automatic ${_BUILD_ARG_JUPYTERLAB_PYTHONBINARY:-python}" true
24+
_BUILD_ARG_PHP="./php/install.sh ${_BUILD_ARG_PHP_VERSION:-latest} /usr/local/php ${_BUILD_ARG_PHP_INSTALLCOMPOSER:-true} true automatic true"

0 commit comments

Comments
 (0)