Description and Setup
I have a problem where some PHP session files are being deleted prior to reaching their session.gc_maxlifetime
threshold.
Operating System: Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-188-generic x86_64)
PHP Version: 7.2.24-0ubuntu0.18.04.12
and some more PHP (php.ini
) configuration:
session.gc_divisor => 10 => 10
session.gc_maxlifetime => 43200 => 43200
session.gc_probability => 1 => 1
session.save_path => /var/lib/php/sessions => /var/lib/php/sessions
session.save_handler => files => files
So I expected to see all sessions older than 12h to be deleted by (I assume) either PHP's garbage collector or this cronjob from PHP (found in /etc/cron.d/php
):
09,39 * * * * root [ -x /usr/lib/php/sessionclean ] && if [ ! -d /run/systemd/system ]; then /usr/lib/php/sessionclean; fi
And deleting session files older than 12h works very well. It's just that some session files for some reason don't last 12h.
Here the contents of the /usr/lib/php/sessionclean
-script being executed by the cronjob (if it helps):
SAPIS="apache2:apache2 apache2filter:apache2 cgi:php@VERSION@ fpm:php-fpm@VERSION@ cli:php@VERSION@"
# Iterate through all web SAPIs
(
proc_names=""
for version in $(/usr/sbin/phpquery -V); do
for sapi in ${SAPIS}; do
conf_dir=${sapi%%:*}
proc_name=${sapi##*:}
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
session_config=$(PHP_INI_SCAN_DIR=/etc/php/${version}/${conf_dir}/conf.d/ php${version} -c /etc/php/${version}/${conf_dir}/php.ini -d "error_reporting='~E_ALL'" -r 'foreach(ini_get_all("session") as $k => $v) echo "$k=".$v["local_value"]."\n";')
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=$(($(echo "$session_config" | sed -ne 's/^session\.gc_maxlifetime=\(.*\)$/\1/p')/60))
if [ "$save_handler" = "files" -a -d "$save_path" ]; then
proc_names="$proc_names $(echo "$proc_name" | sed -e "s,@VERSION@,$version,")";
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 {} \; 2>/dev/null
done ) | \
sort -rn -t: -k2,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 -O3 "$save_path/" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin "+$gc_maxlifetime" -delete
done
exit 0
What I tried
To test how long a session file would persist, I just called/opened my website on a site with the following content and waited:
<?php
session_start();
var_dump( session_id() );
phpinfo();
While waiting I would insert my sessionid
into the following script, which checks every minute whether or not the session file has been deleted:
#! /bin/bash
file=/var/lib/php/sessions/sess_[sessionid]
while test -f "$file"; do
now=$(date +"%T")
echo "$now: $file still exists"
sleep 60
done
now=$(date +"%T")
echo "$now: $file was deleted!"
I observed multiple sessions like this. From the sessions I observed, the session that lastet the longest, didn't even last for 5h. Which is odd, because in the session.save_path
-folder (/var/lib/php/sessions
) are >100 session files which seem to persist for atleast the full 12h.
I have already read the arcticles below, without any success:
- Session should never expire by itself
- How do I expire a PHP session after 30 minutes?
- How to change the session timeout in PHP?
I am stuck with this for 4 days now, any help would be much appreciated.