如何让Linux sessionclean脚本读取php-fpm配置的session.save_path
如何让PHP sessionclean脚本优先读取php-fpm配置中的session.save_path
问题背景
- 目标:让系统内置的
/usr/lib/php/sessionclean脚本,优先使用php-fpm pool配置中php_admin_value[session.save_path]定义的会话路径;若无自定义配置,则 fallback 到默认的/var/lib/php/sessions - 当前问题:该脚本仅从对应PHP版本的
php.ini中读取默认路径,完全忽略php-fpm pool配置里的自定义路径(这也是为什么php -i显示默认路径,但phpinfo页面显示自定义路径的核心原因——PHP CLI进程不会加载fpm pool配置)
问题根源
原脚本通过调用PHP CLI读取配置,但PHP CLI不会加载php-fpm的pool配置文件(通常位于/etc/php/${version}/fpm/pool.d/下的.conf文件),因此无法获取到php_admin_value或php_value覆盖后的session.save_path值。
解决方案:修改sessionclean脚本
我们需要在原脚本中添加逻辑,遍历php-fpm的pool配置文件,提取其中的session.save_path配置并优先使用;若未找到自定义配置,则沿用原逻辑从php.ini读取路径。同时修复原脚本中仅处理最后一个会话路径的touch逻辑bug。
以下是修改后的完整脚本:
#!/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:php@VERSION@ fpm:php-fpm@VERSION@ cli:php@VERSION@" # Iterate through all web SAPIs ( proc_names="" session_paths="" 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" ] && [ -x "/usr/bin/php${version}" ]; 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/ "/usr/bin/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') # 优先从php-fpm pool配置中读取session.save_path fpm_save_path="" if [ "$conf_dir" = "fpm" ]; then # 遍历所有fpm pool配置文件 for pool_conf in /etc/php/${version}/fpm/pool.d/*.conf; do # 提取php_admin_value或php_value中的session.save_path pool_path=$(sed -ne 's/^[[:space:]]*php_admin_value\[session.save_path\][[:space:]]*=[[:space:]]*"\(.*\)"$/\1/p' "$pool_conf") if [ -z "$pool_path" ]; then pool_path=$(sed -ne 's/^[[:space:]]*php_value\[session.save_path\][[:space:]]*=[[:space:]]*"\(.*\)"$/\1/p' "$pool_conf") fi if [ -n "$pool_path" ] && [ -d "$pool_path" ]; then fpm_save_path="$pool_path" break fi done fi # 路径优先级:fpm pool配置 > php.ini配置 if [ -n "$fpm_save_path" ]; then save_path="$fpm_save_path" else save_path=$(echo "$session_config" | sed -ne 's/^session\.save_path=\(.*;\)\?\(.*\)$/\2/p') fi gc_maxlifetime=$(($(echo "$session_config" | sed -ne 's/^session\.gc_maxlifetime=\(.*\)$/\1/p')/60)) if [ "$save_handler" = "files" ] && [ -d "$save_path" ]; then proc_names="$proc_names $(echo "$proc_name" | sed -e "s,@VERSION@,$version,")"; printf "%s:%s\n" "$save_path" "$gc_maxlifetime" # 保存所有有效会话路径,用于后续更新open session时间戳 session_paths="$session_paths$save_path"$'\n' fi fi done done # 更新所有open session文件的时间戳,避免被误清理 for pid in $(pidof $proc_names); do while IFS= read -r sp; do [ -z "$sp" ] && continue find "/proc/$pid/fd" -ignore_readdir_race -lname "$sp/sess_*" -exec touch -c {} \; 2>/dev/null done <<EOF $session_paths EOF done ) | \ sort -rn -t: -k2,2 | \ sort -u -t: -k 1,1 | \ while IFS=: read -r save_path gc_maxlifetime; do # 删除过期会话文件 find -O3 "$save_path/" -ignore_readdir_race -depth -mindepth 1 -name 'sess_*' -type f -cmin "+$gc_maxlifetime" -delete done exit 0
关键修改说明
- 添加fpm pool配置读取逻辑:当处理fpm类型的SAPI时,遍历
/etc/php/${version}/fpm/pool.d/下的所有.conf文件,优先提取php_admin_value[session.save_path]的值,若不存在则尝试php_value[session.save_path] - 路径优先级处理:优先使用fpm pool配置中的路径,无自定义配置时才使用php.ini中的默认路径
- 修复open session时间戳更新逻辑:原脚本仅处理最后一个会话路径的进程文件,修改为遍历所有收集到的有效路径,确保所有正在使用的会话文件都不会被误清理
验证方法
- 替换原脚本后,确保执行权限正常:
chmod +x /usr/lib/php/sessionclean - 手动执行脚本:
/usr/lib/php/sessionclean - 检查自定义会话路径下的过期文件是否被正确清理
内容的提问来源于stack exchange,提问作者Saad Ahmed
相关产品推荐
相关产品推荐

