YANZ UPLOAD ANJG
#!/bin/bash
# i360-altphp-activate - put "extension=i360.so" where alt-php reads it.
#
# The location is decided from /usr/share/i360-php-opts/cagefs.ini on every run and
# is never stored:
# on - /opt/alt/phpXX/etc/php.ini
# off - /opt/alt/phpXX/etc/php.d/i360.ini
# auto - php.d/i360.ini on a Plesk host that has neither CageFS nor CloudLinux,
# php.ini everywhere else (the shipped default). A missing file or an
# unrecognised value is read as auto, so one typo cannot leave a host
# unprotected.
#
# Why two locations (DEF-34424, DEF-52216): inside a CageFS cage the PHP Selector
# swaps /opt/alt/phpXX/link/conf for the tenant's own directory, so php.d/i360.ini is
# never read there and php.ini is the only file every caged PHP reads that a tenant
# cannot edit. On a Plesk host without CageFS nothing swaps that directory: php.d/i360.ini
# is read by every SAPI and, unlike a line appended to php.ini, it survives Plesk's
# tuxcare-php extension, which replaces php.ini wholesale on every install/configure/switch.
#
# Only Plesk-without-CageFS moves. Every cPanel, DirectAdmin and panel-less host keeps
# php.ini, and so does every CloudLinux host whether or not CageFS is installed yet.
# A host that gains CageFS later is moved back to php.ini at the next package event:
# %post of imunify360-php-i360, %triggerin on alt-phpXX-common, %triggerin on cagefs.
# The steps are the ones the spec used to carry inline in %post and %triggerin.
#
# On Plesk every run also brings the per-site php.ini of each site on that version's CGI or
# FastCGI handler in line with it (sync_plesk_site_ini).
#
# Usage: i360-altphp-activate [phpXX ...]
# Without arguments every version listed in /usr/share/i360-php/altphps.txt is handled.
#
# Exit status is always 0.
KNOB=/usr/share/i360-php-opts/cagefs.ini
VERSIONS_FILE=/usr/share/i360-php/altphps.txt
PLESK=/usr/sbin/plesk
# Versions this run handled.
HANDLED=()
# A cage swaps the php.d scan directory out from under us for every tenant who selected a
# PHP version, so php.ini is the only location that reaches all of them. CageFS ships only
# on CloudLinux and a CloudLinux host can install it at any moment, so either signal is
# enough to keep the host on php.ini.
needs_php_ini() {
[ -e /usr/sbin/cagefsctl ] && return 0
# CloudLinux 10 keeps AlmaLinux's os-release; cloudlinux-release still marks it.
[ -e /etc/cloudlinux-release ] && return 0
grep -qsi cloudlinux /etc/os-release /etc/redhat-release
}
# The house test for Plesk, same as the spec's %post and %preun.
is_plesk() {
[ -e /usr/local/psa/version ]
}
# Prints "php.ini" or "php.d".
delivery_mode() {
local knob
knob=$(sed -n 's/^cagefs_integration=[[:space:]]*//p' "$KNOB" 2>/dev/null | tail -n1)
knob=${knob%%[[:space:]]*}
case "$knob" in
off) echo php.d ;;
on) echo php.ini ;;
*) if needs_php_ini; then echo php.ini
elif is_plesk; then echo php.d
else echo php.ini
fi ;;
esac
}
enable_in_php_ini() {
local ver=$1 etc=/opt/alt/$1/etc
# Write the new location before clearing the old one: the transient state is then
# "loaded twice", which costs a warning, rather than "not loaded", which costs cover.
if ! grep -qs i360.so "$etc/php.ini"; then
# Keep the old location if the write fails.
cat "$etc/php.d.i360/i360.ini" >> "$etc/php.ini" || return 0
echo "i360: $ver: extension=i360.so enabled in $etc/php.ini"
fi
# Not conditional on the append above: with the line in php.ini *and* a copy in php.d
# the module loads twice for good. And with i360 in the places the PHP Selector
# manages, 'selectorctl --user user --set-user-current 8.2' turns i360 off (DEF-34424).
if grep -qs i360 /opt/alt/"$ver"/link/conf/default.ini; then
sed -i -e '/i360\./d' -e '/\[i360\]/d' /opt/alt/"$ver"/link/conf/default.ini
fi
rm -f "$etc/php.d/i360.ini" "$etc/php.d.all/i360.ini"
}
enable_in_php_d() {
local ver=$1 etc=/opt/alt/$1/etc
# Same order as above, for the same reason. Copied only when absent, so a drop-in the
# administrator commented out with 'plesk bin php_modules_ctl -d i360' stays commented.
if [ ! -f "$etc/php.d/i360.ini" ]; then
# Through a temporary name: a copy cut short must not leave a php.d/i360.ini that the next
# run would take for a finished one.
mkdir -p "$etc/php.d" && cp "$etc/php.d.i360/i360.ini" "$etc/php.d/.i360.ini.new" &&
mv -fT "$etc/php.d/.i360.ini.new" "$etc/php.d/i360.ini" ||
{ rm -f "$etc/php.d/.i360.ini.new"; return 0; }
echo "i360: $ver: extension=i360.so enabled in $etc/php.d/i360.ini"
fi
if grep -qs i360 "$etc/php.ini"; then
sed -i -e '/i360\./d' -e '/\[i360\]/d' "$etc/php.ini"
echo "i360: $ver: extension=i360.so removed from $etc/php.ini"
fi
}
# Plesk's CGI and FastCGI handlers do not read /opt/alt/phpXX/etc/php.ini: each site reads a copy
# Plesk renders into /system//etc/php.ini from that file plus the site's own settings,
# and re-renders only when the site's PHP settings are saved. Our line reaches the copy as
# "extension = i360.so" under [PHP]. Left alone, a php.ini -> php.d move loads i360 twice on those
# sites and a php.d -> php.ini move leaves them without it, so make each copy agree with its
# version's php.ini, which is what the next render would write anyway. mod_fcgid recycles the PHP
# processes within minutes, so nothing needs a restart.
sync_plesk_site_ini() {
local ids= v site handler ver ini vhosts
is_plesk && [ -x "$PLESK" ] || return 0
vhosts=$(sed -n 's/^HTTPD_VHOSTS_D[[:space:]]\+//p' /etc/psa/psa.conf 2>/dev/null)
for v in "$@"; do ids="$ids,'alt-$v-cgi','alt-$v-fastcgi'"; done
"$PLESK" db -Ne "SELECT d.name, h.php_handler_id FROM domains d JOIN hosting h ON h.dom_id = d.id WHERE h.php_handler_id IN (${ids#,})" 2>/dev/null |
while read -r site handler; do
ini=${vhosts:-/var/www/vhosts}/system/$site/etc/php.ini
[ -f "$ini" ] || continue
ver=${handler#alt-}; ver=${ver%-*}
if grep -qs '^[[:space:]]*extension[[:space:]]*=[[:space:]]*"\?i360\.so' "/opt/alt/$ver/etc/php.ini"; then
grep -qs '^extension[[:space:]]*=[[:space:]]*"\?i360\.so' "$ini" && continue
sed -i '/^\[PHP\]$/a extension = i360.so' "$ini" &&
echo "i360: $site: extension=i360.so enabled in $ini"
elif grep -qs '^extension[[:space:]]*=[[:space:]]*"\?i360\.so' "$ini"; then
sed -i '/^extension[[:space:]]*=[[:space:]]*"\?i360\.so/d' "$ini" &&
echo "i360: $site: extension=i360.so removed from $ini"
fi
done
}
main() {
local versions=("$@") mode ver etc
if [ ${#versions[@]} -eq 0 ]; then
[ -r "$VERSIONS_FILE" ] || exit 0
read -r -a versions < "$VERSIONS_FILE"
fi
mode=$(delivery_mode)
for ver in "${versions[@]}"; do
[[ $ver =~ ^php[0-9]{2,3}$ ]] || continue
etc=/opt/alt/$ver/etc
# alt-php version not installed, or i360 not shipped for it: nothing to do.
[ -e "$etc/php.ini" ] && [ -e "$etc/php.d.i360/i360.ini" ] || continue
case $mode in
php.ini) enable_in_php_ini "$ver" ;;
php.d) enable_in_php_d "$ver" ;;
esac
HANDLED+=("$ver")
done
[ ${#HANDLED[@]} -eq 0 ] || sync_plesk_site_ini "${HANDLED[@]}"
exit 0
}
main "$@"