Created
October 21, 2026 06:26
-
-
Save stayallive/588062a3ece006b51d3fee00c57c1bea to your computer and use it in GitHub Desktop.
Disable session.upload_progress.enabled for every PHP-FPM version
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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