Skip to content

Instantly share code, notes, and snippets.

@szepeviktor
Last active June 28, 2021 02:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szepeviktor/fc916136216a33430a1e to your computer and use it in GitHub Desktop.
Save szepeviktor/fc916136216a33430a1e to your computer and use it in GitHub Desktop.
#!/bin/sh -e
#
# sessionclean - a script to cleanup stale PHP sessions
#
# Copyright 2013-2015 Ondřej Surý <ondrej@sury.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SAPIS="apache2:apache2
apache2filter:apache2
cgi:php5
fpm:php5-fpm"
PHP_DUMP_SESSION='foreach(ini_get_all("session") as $k => $v) echo "$k=".$v["local_value"]."\n";'
# Iterate through all web SAPIs
(
for version in $(/usr/sbin/phpquery -V); do
proc_names=""
echo "$SAPIS" \
| while IFS=: read -r conf_dir proc_name; do
if [ -e "/etc/php/${version}/${conf_dir}/php.ini" ]; then
# Get all session variables once so we don't need to start PHP to get each config option
abs_conf_dir="/etc/php/${version}/${conf_dir}"
session_config=$(PHP_INI_SCAN_DIR="${abs_conf_dir}/conf.d/" "php${version}" -c "${abs_conf_dir}/php.ini" -d "error_reporting='~E_ALL'" -r "$PHP_DUMP_SESSION")
save_handler=$(echo "$session_config" | sed -ne 's/^session\.save_handler=\(.*\)$/\1/p')
save_path=$(echo "$session_config" | sed -ne 's/^session\.save_path=\(.*;\)\?\(.*\)$/\2/p')
gc_maxlifetime_sec="$(echo "$session_config" | sed -ne 's/^session\.gc_maxlifetime=\(.*\)$/\1/p')"
gc_maxlifetime=$((gc_maxlifetime_sec / 60))
if [ "$save_handler" = "files" -a -d "$save_path" ]; then
proc_names="$proc_names $proc_name"
printf "%s:%s\n" "$save_path" "$gc_maxlifetime"
fi
fi
done
done
# First find all open session files and touch them (hope it's not massive amount of files)
for pid in $(pidof $proc_names); do
find "/proc/$pid/fd" -ignore_readdir_race -lname "${save_path}/sess_*" -exec touch -c "{}" ";"
done
) \
| sort -r -n -t ":" -k 2,2 \
| sort -u -t ":" -k 1,1 \
| while IFS=":" read -r save_path gc_maxlifetime; do
# Find all files older then maxlifetime and delete them
find -O 3 "${save_path}/" -depth -ignore_readdir_race -mindepth 1 -name "sess_*" -type f -cmin "+${gc_maxlifetime}" -delete
done
exit 0
@CODE-REaD
Copy link

I tested this script and found that the for loop starting at line 55 never executes. The reason is $proc_names is never populated at this point. I think this is because the inner do loop starting at line 36 runs in a subshell because it is fed by the pipe on that same line.

So I don't think the touch logic on line 63 is ever invoked.

To correct this, I think we could move the for loop at lines 54..57 to just after line 47 (proc_names="$proc_names $proc_name").

@szepeviktor
Copy link
Author

I tested this script and found that the for loop starting at line 55 never executes.

Yes, this was a problem in the Debian script: https://salsa.debian.org/php-team/php-defaults/commit/62c00a154f854a6d5f56984b82f11b5ce1540bb8

This gist is OLD.

@CODE-REaD
Copy link

Thanks, that is the exact problem I was attempting to describe!
I wonder how I could have found the newer version of this project without your help. (I went through the first 5 Google results for php "sessionclean" shell script; this page was Google's second match.) Any help appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment