Skip to content

Instantly share code, notes, and snippets.

@stayallive
Created October 21, 2026 06:26
Show Gist options
  • Select an option

  • Save stayallive/588062a3ece006b51d3fee00c57c1bea to your computer and use it in GitHub Desktop.

Select an option

Save stayallive/588062a3ece006b51d3fee00c57c1bea to your computer and use it in GitHub Desktop.
Disable session.upload_progress.enabled for every PHP-FPM version
#!/usr/bin/env bash
#
# Disable session.upload_progress.enabled for every PHP-FPM version under /etc/php.
# Versions that already have it disabled are left untouched (no backup, no reload).
# Each version is handled independently: a failure is logged, that version's php.ini
# is restored from its backup, and the script moves on to the next version.
set -Eeuo pipefail
shopt -s nullglob
readonly LOG_FILE=/var/log/php-disable-upload-progress.log
readonly SETTING_RE='^[[:space:]]*;?[[:space:]]*session\.upload_progress\.enabled[[:space:]]*='
readonly ERR_TRAP='on_error $? $LINENO "$BASH_COMMAND"'
log() { printf '%s [%-5s] %s\n' "$(date '+%F %T')" "$1" "$2"; }
info() { log INFO "$*"; }
warn() { log WARN "$*" >&2; }
error() { log ERROR "$*" >&2; }
die() { error "$*"; exit 1; }
on_error() {
error "Command failed with exit code $1 at line $2: $3"
}
# Prints "<file>\t<value>" for the last active (uncommented) assignment of
# session.upload_progress.enabled across the given files, in load order.
# Prints nothing when the setting is never set (PHP's default is On).
effective_setting() {
awk '
/^[ \t]*session\.upload_progress\.enabled[ \t]*=/ {
v = $0
sub(/^[^=]*=/, "", v)
sub(/;.*/, "", v)
gsub(/[ \t"\047]/, "", v)
file = FILENAME
value = tolower(v)
}
END { if (file != "") printf "%s\t%s\n", file, value }
' "$@"
}
is_off() {
case "$1" in
off|0|false|no|none|"") return 0 ;;
*) return 1 ;;
esac
}
# Runs in its own subshell (see main loop), so these variables don't leak between versions.
configure_version() {
ini=$1
version=$(basename "$(dirname "$(dirname "$ini")")")
service="php${version}-fpm"
conf_d="$(dirname "$ini")/conf.d"
backup=""
rollback=0
src=""
value=""
# Put the original php.ini back if anything fails after we touched it
trap '
rc=$?
if [[ $rc -ne 0 && $rollback -eq 1 ]]; then
warn "PHP ${version}: restoring original php.ini from ${backup}"
cp -p "$backup" "$ini"
fi
' EXIT
info "PHP ${version}: checking ${ini}"
fpm_bin=$(command -v "php-fpm${version}" || command -v "/usr/sbin/php-fpm${version}" || true)
if [[ -z $fpm_bin ]]; then
warn "PHP ${version}: php-fpm${version} not found (leftover config from a removed package?), skipping"
return 0
fi
# Check before doing anything, including the backup
IFS=$'\t' read -r src value < <(effective_setting "$ini" "$conf_d"/*.ini) || true
if [[ -n $src ]] && is_off "$value"; then
info "PHP ${version}: already disabled (${src}), nothing to do"
return 0
fi
if [[ -n $src && $src != "$ini" ]]; then
die "PHP ${version}: enabled by ${src}, which overrides php.ini; change it there instead"
fi
backup="${ini}.bak.$(date +%Y%m%d%H%M%S)"
cp -p "$ini" "$backup"
rollback=1
info "PHP ${version}: backup written to ${backup}"
if grep -Eq "$SETTING_RE" "$ini"; then
sed -Ei "s/${SETTING_RE}.*/session.upload_progress.enabled = Off/" "$ini"
else
printf '\nsession.upload_progress.enabled = Off\n' >> "$ini"
fi
# Make sure the edit actually resulted in Off
IFS=$'\t' read -r src value < <(effective_setting "$ini" "$conf_d"/*.ini) || true
if [[ -z $src ]] || ! is_off "$value"; then
die "PHP ${version}: setting is still not Off after editing ${ini}"
fi
if ! test_output=$("$fpm_bin" -t 2>&1); then
printf '%s\n' "$test_output" >&2
die "PHP ${version}: configuration test failed"
fi
if systemctl is-active --quiet "$service"; then
systemctl reload "$service"
info "PHP ${version}: ${service} reloaded"
else
warn "PHP ${version}: ${service} is not running, skipping reload"
fi
rollback=0
info "PHP ${version}: upload progress disabled"
}
if [[ $EUID -ne 0 ]]; then
echo "Run this script as root." >&2
exit 1
fi
exec > >(tee -a "$LOG_FILE") 2>&1
trap "$ERR_TRAP" ERR
inis=(/etc/php/*/fpm/php.ini)
if [[ ${#inis[@]} -eq 0 ]]; then
warn "No PHP-FPM php.ini files found under /etc/php"
exit 0
fi
failed=()
for ini in "${inis[@]}"; do
# Own subshell per version so one failure doesn't abort the rest.
# The parent's ERR trap is paused so the failure isn't logged twice.
trap - ERR
set +e
( set -e; trap "$ERR_TRAP" ERR; configure_version "$ini" )
rc=$?
set -e
trap "$ERR_TRAP" ERR
if [[ $rc -ne 0 ]]; then
failed+=("$(basename "$(dirname "$(dirname "$ini")")")")
fi
done
if [[ ${#failed[@]} -gt 0 ]]; then
error "Finished with failures for PHP ${failed[*]} (log: ${LOG_FILE})"
exit 1
fi
info "Done!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment