#!/bin/bash ################################################################################ # PHP Detector Library # Part of Server Toolkit - PHP & Server Optimizer # # Purpose: Detect all PHP configurations, pools, versions, and settings # Author: Server Toolkit Team # Dependencies: system-detect.sh, user-manager.sh ################################################################################ # Source dependencies (if not already loaded) if [ -z "$SYS_CONTROL_PANEL" ]; then _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "$_LIB_DIR/lib/system-detect.sh" 2>/dev/null source "$_LIB_DIR/lib/user-manager.sh" 2>/dev/null fi ################################################################################ # PHP Version Detection ################################################################################ # Detect all installed PHP versions on the system detect_installed_php_versions() { local -a php_versions=() # cPanel EA-PHP if [ -d "/opt/cpanel" ]; then while IFS= read -r dir; do local version=$(basename "$dir" | sed 's/ea-php//') php_versions+=("ea-php$version") done < <(find /opt/cpanel -maxdepth 1 -type d -name "ea-php*" 2>/dev/null | sort) fi # CloudLinux Alt-PHP if [ -d "/opt/alt" ]; then while IFS= read -r dir; do local version=$(basename "$dir" | sed 's/php//') php_versions+=("alt-php$version") done < <(find /opt/alt -maxdepth 1 -type d -name "php*" 2>/dev/null | grep -E "php[0-9]" | sort) fi # Plesk PHP if [ -d "/opt/plesk/php" ]; then while IFS= read -r dir; do local version=$(basename "$dir") php_versions+=("plesk-php$version") done < <(find /opt/plesk/php -maxdepth 1 -type d -name "[0-9]*" 2>/dev/null | sort) fi # System PHP if command -v php &>/dev/null; then local sys_version=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null) [ -n "$sys_version" ] && php_versions+=("system-php$sys_version") fi # Return array printf '%s\n' "${php_versions[@]}" } # Get PHP version for a specific domain/user detect_php_version_for_domain() { local username="$1" local domain="$2" case "$SYS_CONTROL_PANEL" in cpanel) # Check userdata for PHP version local userdata_file="${SYS_CPANEL_USERDATA_DIR:-/var/cpanel/userdata}/$username/$domain" if [ -f "$userdata_file" ]; then local php_ver=$(grep "phpversion:" -- "$userdata_file" | awk '{print $2}' | tr -d "'\"") echo "$php_ver" return 0 fi # Fallback: Check FPM pool config local pool_config=$(find /opt/cpanel/ea-php*/root/etc/php-fpm.d/ -name "$username.conf" 2>/dev/null | head -1) if [ -n "$pool_config" ]; then local php_path=$(dirname "$(dirname "$(dirname "$pool_config")")") basename "$php_path" return 0 fi ;; plesk) # Query Plesk database if command -v plesk &>/dev/null; then plesk bin site -i "$domain" 2>/dev/null | grep "PHP version" | awk '{print $NF}' return 0 fi ;; interworx) # Check SiteWorx config local domain_conf="/home/$username/var/$domain/siteworx.conf" if [ -f "$domain_conf" ]; then grep "php_version" "$domain_conf" | cut -d'=' -f2 return 0 fi ;; esac # Fallback: Try to execute PHP as user su -s /bin/bash "$username" -c "php -r 'echo PHP_MAJOR_VERSION.\".\".PHP_MINOR_VERSION;'" 2>/dev/null } ################################################################################ # PHP Configuration File Detection ################################################################################ # Find ALL php.ini files affecting a domain (in priority order) find_all_php_configs() { local username="$1" local domain="$2" local php_version="${3:-}" # Optional: e.g., "82" or "8.2" or "ea-php82" declare -a config_files=() # Normalize PHP version format local php_ver_short=$(echo "$php_version" | grep -oE '[0-9]+' | head -c2) local php_ver_dot="${php_ver_short:0:1}.${php_ver_short:1}" # PRIORITY 1: Per-Directory .user.ini files if [ -d "/home/$username" ]; then while IFS= read -r file; do config_files+=("P1|$file|.user.ini") done < <(find "/home/$username" -name ".user.ini" -type f 2>/dev/null) fi # Check Plesk domain root if [ -d "/var/www/vhosts/$domain" ]; then while IFS= read -r file; do config_files+=("P1|$file|.user.ini") done < <(find "/var/www/vhosts/$domain" -name ".user.ini" -type f 2>/dev/null) fi # PRIORITY 2: User-Specific php.ini files local user_configs=( "/home/$username/public_html/php.ini" "/home/$username/php.ini" "/home/$username/.php/$php_ver_dot/php.ini" "/home/$username/.php/$php_ver_short/php.ini" "/home/$username/etc/php.ini" "/home/$username/etc/php$php_ver_short/php.ini" "/home/$username/var/$domain/etc/php.ini" # InterWorx "/var/www/vhosts/system/$domain/etc/php.ini" # Plesk ) for config in "${user_configs[@]}"; do [ -f "$config" ] && config_files+=("P2|$config|user php.ini") done # PRIORITY 3: Pool/Version-Specific php.ini if [ -n "$php_ver_short" ]; then # cPanel EA-PHP local cpanel_ini="/opt/cpanel/ea-php${php_ver_short}/root/etc/php.ini" [ -f "$cpanel_ini" ] && config_files+=("P3|$cpanel_ini|pool php.ini") # cPanel EA-PHP additional .ini files if [ -d "/opt/cpanel/ea-php${php_ver_short}/root/etc/php.d" ]; then while IFS= read -r file; do config_files+=("P3|$file|pool php.d") done < <(find "/opt/cpanel/ea-php${php_ver_short}/root/etc/php.d" -name "*.ini" -type f 2>/dev/null | sort) fi # CloudLinux Alt-PHP local alt_ini="/opt/alt/php${php_ver_short}/etc/php.ini" [ -f "$alt_ini" ] && config_files+=("P3|$alt_ini|alt-php ini") # Plesk PHP local plesk_ini="/opt/plesk/php/$php_ver_dot/etc/php.ini" [ -f "$plesk_ini" ] && config_files+=("P3|$plesk_ini|plesk php.ini") fi # PRIORITY 4: System-Wide [ -f "/etc/php.ini" ] && config_files+=("P4|/etc/php.ini|system php.ini") # Return the array (priority|path|description) printf '%s\n' "${config_files[@]}" } # Get effective value of a PHP setting for a specific user get_effective_php_setting() { local username="$1" local setting="$2" # Query PHP directly as the user (most accurate!) su -s /bin/bash "$username" -c "php -r 'echo ini_get(\"$setting\");'" 2>/dev/null } # Get all effective PHP settings for a user get_all_php_settings() { local username="$1" # Get all settings in parseable format su -s /bin/bash "$username" -c "php -r 'foreach(ini_get_all() as \$k=>\$v) { echo \$k.\"=\".\$v[\"local_value\"].\"\\n\"; }'" 2>/dev/null } ################################################################################ # PHP-FPM Pool Detection ################################################################################ # Find PHP-FPM pool configuration for a user/domain find_fpm_pool_config() { local username="$1" local domain="$2" local php_version="${3:-}" local pool_config="" # cPanel EA-PHP pools - search username FIRST (this is how cPanel works!) if [ -n "$php_version" ]; then # Try username-based config (most common) pool_config="/opt/cpanel/$php_version/root/etc/php-fpm.d/$username.conf" [ -f "$pool_config" ] && echo "$pool_config" && return 0 # Try domain-based config (rare, but possible) if [ -n "$domain" ]; then pool_config="/opt/cpanel/$php_version/root/etc/php-fpm.d/$domain.conf" [ -f "$pool_config" ] && echo "$pool_config" && return 0 fi fi # Search all EA-PHP versions - try username FIRST, then domain pool_config=$(find /opt/cpanel/ea-php*/root/etc/php-fpm.d/ -name "$username.conf" 2>/dev/null | head -1) [ -n "$pool_config" ] && echo "$pool_config" && return 0 if [ -n "$domain" ]; then pool_config=$(find /opt/cpanel/ea-php*/root/etc/php-fpm.d/ -name "$domain.conf" 2>/dev/null | head -1) [ -n "$pool_config" ] && echo "$pool_config" && return 0 fi # Plesk pools if [ -n "$domain" ]; then pool_config="/etc/php-fpm.d/plesk-php*-fpm/$domain.conf" [ -f "$pool_config" ] && echo "$pool_config" && return 0 fi # InterWorx pools if [ -n "$domain" ]; then pool_config="/home/$username/var/$domain/php-fpm.conf" [ -f "$pool_config" ] && echo "$pool_config" && return 0 fi return 1 } # Parse PHP-FPM pool config and extract all settings parse_fpm_pool_config() { local pool_config="$1" [ ! -f "$pool_config" ] && return 1 # Extract key settings local pm=$(grep "^pm\s*=" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local max_children=$(grep "^pm.max_children" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local start_servers=$(grep "^pm.start_servers" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local min_spare=$(grep "^pm.min_spare_servers" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local max_spare=$(grep "^pm.max_spare_servers" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local max_requests=$(grep "^pm.max_requests" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local idle_timeout=$(grep "^pm.process_idle_timeout" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local request_terminate=$(grep "^request_terminate_timeout" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') local slowlog_timeout=$(grep "^request_slowlog_timeout" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') # Output in key=value format echo "pm=$pm" echo "pm.max_children=$max_children" echo "pm.start_servers=$start_servers" echo "pm.min_spare_servers=$min_spare" echo "pm.max_spare_servers=$max_spare" echo "pm.max_requests=$max_requests" echo "pm.process_idle_timeout=$idle_timeout" echo "request_terminate_timeout=$request_terminate" echo "request_slowlog_timeout=$slowlog_timeout" } # Get current FPM process count for a pool get_fpm_process_count() { [ -z "$1" ] && return 1 local pool_name="$1" # Usually username or domain local count=$(ps aux | grep -E "php-fpm.*pool\s+${pool_name}" | grep -v grep | wc -l || echo 0) echo "$count" } # Get memory usage per FPM process for a pool get_fpm_memory_usage() { [ -z "$1" ] && return 1 local pool_name="$1" # Get average memory per process (in KB) ps aux | grep -E "php-fpm.*pool\s+${pool_name}" | grep -v grep | awk '{sum+=$6; count++} END {if(count>0) print int(sum/count); else print 0}' } ################################################################################ # PHP Log File Detection ################################################################################ # Find PHP error logs for a user/domain find_php_error_logs() { local username="$1" local domain="$2" declare -a log_files=() # Common error log locations local possible_logs=( "/home/$username/logs/error_log" "/home/$username/public_html/error_log" "/home/$username/logs/$domain.error_log" "/var/www/vhosts/$domain/logs/error_log" "/home/$username/var/$domain/logs/error_log" ) for log in "${possible_logs[@]}"; do [ -f "$log" ] && log_files+=("$log") done printf '%s\n' "${log_files[@]}" } # Find PHP-FPM error logs find_fpm_error_logs() { local username="$1" local php_version="${2:-}" declare -a log_files=() if [ -n "$php_version" ]; then # Specific version log_files+=("/opt/cpanel/$php_version/root/usr/var/log/php-fpm/$username-error.log") else # All versions while IFS= read -r log; do log_files+=("$log") done < <(find /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/ -name "$username-error.log" 2>/dev/null) fi printf '%s\n' "${log_files[@]}" } # Find PHP-FPM slow logs find_fpm_slow_logs() { local username="$1" local php_version="${2:-}" declare -a log_files=() if [ -n "$php_version" ]; then log_files+=("/opt/cpanel/$php_version/root/usr/var/log/php-fpm/$username-slow.log") else while IFS= read -r log; do log_files+=("$log") done < <(find /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/ -name "$username-slow.log" 2>/dev/null) fi printf '%s\n' "${log_files[@]}" } ################################################################################ # OPcache Detection ################################################################################ # Check if OPcache is enabled for a user check_opcache_enabled() { local username="$1" su -s /bin/bash "$username" -c "php -r 'echo (function_exists(\"opcache_get_status\") && opcache_get_status() !== false) ? \"1\" : \"0\";'" 2>/dev/null } # Get OPcache statistics for a user get_opcache_stats() { local username="$1" su -s /bin/bash "$username" -c "php -r 'if(function_exists(\"opcache_get_status\")) { \$s=opcache_get_status(); echo \"enabled=\".(\$s!==false?1:0).\"\\n\"; if(\$s) { echo \"memory_used=\".\$s[\"memory_usage\"][\"used_memory\"].\"\\n\"; echo \"memory_free=\".\$s[\"memory_usage\"][\"free_memory\"].\"\\n\"; echo \"memory_wasted=\".\$s[\"memory_usage\"][\"wasted_memory\"].\"\\n\"; echo \"num_cached_scripts=\".\$s[\"opcache_statistics\"][\"num_cached_scripts\"].\"\\n\"; echo \"max_cached_scripts=\".\$s[\"opcache_statistics\"][\"max_cached_scripts\"].\"\\n\"; echo \"hits=\".\$s[\"opcache_statistics\"][\"hits\"].\"\\n\"; echo \"misses=\".\$s[\"opcache_statistics\"][\"misses\"].\"\\n\"; } }'" 2>/dev/null } # Calculate OPcache hit rate calculate_opcache_hit_rate() { local username="$1" local stats=$(get_opcache_stats "$username") [ -z "$stats" ] && echo "0" && return 1 local hits=$(echo "$stats" | grep "^hits=" | cut -d'=' -f2) local misses=$(echo "$stats" | grep "^misses=" | cut -d'=' -f2) [ -z "$hits" ] || [ -z "$misses" ] && echo "0" && return 1 [ "$hits" -eq 0 ] && [ "$misses" -eq 0 ] && echo "0" && return 1 local total=$((hits + misses)) local hit_rate=$((hits * 100 / total)) echo "$hit_rate" } ################################################################################ # Helper Functions ################################################################################ # Check if PHP-FPM is in use (vs mod_php) is_using_php_fpm() { # Check if any PHP-FPM processes are running pgrep php-fpm &>/dev/null && return 0 return 1 } # Get PHP binary path for a specific version get_php_binary_path() { local php_version="$1" case "$php_version" in ea-php*) echo "/opt/cpanel/$php_version/root/usr/bin/php" ;; alt-php*) local ver=$(echo "$php_version" | sed 's/alt-php//') echo "/opt/alt/php$ver/usr/bin/php" ;; plesk-php*) local ver=$(echo "$php_version" | sed 's/plesk-php//') echo "/opt/plesk/php/$ver/bin/php" ;; *) which php ;; esac } # Export all functions export -f detect_installed_php_versions export -f detect_php_version_for_domain export -f find_all_php_configs export -f get_effective_php_setting export -f get_all_php_settings export -f find_fpm_pool_config export -f parse_fpm_pool_config export -f get_fpm_process_count export -f get_fpm_memory_usage export -f find_php_error_logs export -f find_fpm_error_logs export -f find_fpm_slow_logs export -f check_opcache_enabled export -f get_opcache_stats export -f calculate_opcache_hit_rate export -f is_using_php_fpm export -f get_php_binary_path