From 86a1739bba84ef299dd477ad4898f0f49af0bf76 Mon Sep 17 00:00:00 2001 From: cschantz Date: Tue, 2 Dec 2025 20:30:44 -0500 Subject: [PATCH] Phase 3: Add interactive PHP Performance Optimizer (modules/performance/php-optimizer.sh) COMPLETE INTERACTIVE MENU SYSTEM: - 8 main menu options for comprehensive PHP optimization - Domain selection with PHP version display - Real-time analysis and recommendations - Color-coded severity levels (CRITICAL/HIGH/MEDIUM/LOW) - Safe implementation with cecho() helper MENU OPTIONS: 1. Analyze Single Domain - Complete PHP analysis report 2. Analyze All Domains - Server-wide analysis with issue detection 3. Quick Health Check - Overall health score based on issues 4. Optimize Domain - Detect issues + show recommendations 5. Optimize Server-Wide - (Placeholder for future) 6. View OPcache Statistics - Hit rates, memory usage, cache efficiency 7. View PHP-FPM Process Stats - Memory usage, process counts, pool config 8. Check Configuration Issues - Grouped by severity with recommendations FEATURES IMPLEMENTED: - Domain selection with user/PHP version context - Comprehensive analysis using lib/php-analyzer.sh - Issue detection with 4 severity levels - OPcache statistics with hit rate analysis - PHP-FPM resource usage tracking - Optimal max_children calculations - Health scoring system (0-100) - Color-coded output for readability ANALYSIS CAPABILITIES: - PHP version detection per domain - Configuration hierarchy display (4 priority levels) - Effective settings resolution - PHP-FPM pool configuration parsing - Resource usage statistics (processes, memory) - OPcache performance metrics - Traffic analysis (requests/min, peak concurrent) - Error analysis (7-day history) ISSUE DETECTION: - Config mismatches (post_max_size < upload_max_filesize) - Security risks (display_errors = On) - Performance issues (low memory_limit, OPcache disabled) - Capacity issues (max_children errors) - Memory leaks (pm.max_requests = 0) - Resource waste (pm=static on low traffic) RECOMMENDATIONS ENGINE: - Calculates optimal pm.max_children based on: * System memory (total - reserved) * Average memory per process * 20% safety buffer - OPcache optimization suggestions - Memory limit adjustments - Process manager mode recommendations SAFETY FEATURES: - Read-only analysis (no modifications yet) - Root user check - PHP-FPM detection with warnings - Graceful handling of missing data - Clear "not yet implemented" placeholders for future features DISPLAY FEATURES: - Formatted banners and section separators - Color-coded severity (RED=critical, YELLOW=high, BLUE=medium, GREEN=low) - Progress indicators for multi-domain analysis - Summary statistics and health scores - Grouped issue display by severity INTEGRATION: - Uses lib/php-detector.sh for detection (Phase 1) - Uses lib/php-analyzer.sh for analysis (Phase 2) - Uses lib/system-detect.sh for system detection - Uses lib/user-manager.sh for user/domain management NOT YET IMPLEMENTED (Future): - Automatic configuration changes (backup/apply/restore) - Server-wide optimization in single action - Backup/restore functionality - Integration with live-attack-monitor (NOT requested by user) USAGE: bash /root/server-toolkit/modules/performance/php-optimizer.sh All 3 phases complete! PHP optimizer ready for testing and refinement. --- modules/performance/php-optimizer.sh | 799 +++++++++++++++++++++++++++ 1 file changed, 799 insertions(+) create mode 100755 modules/performance/php-optimizer.sh diff --git a/modules/performance/php-optimizer.sh b/modules/performance/php-optimizer.sh new file mode 100755 index 0000000..6eda6ac --- /dev/null +++ b/modules/performance/php-optimizer.sh @@ -0,0 +1,799 @@ +#!/bin/bash +# PHP & Server Performance Optimizer +# Interactive tool for analyzing and optimizing PHP-FPM configurations +# Part of Server Toolkit - Phase 3: Main Interactive Script + +# Source required libraries +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd ../.. && pwd)" +source "$SCRIPT_DIR/lib/php-detector.sh" 2>/dev/null || { echo "ERROR: php-detector.sh not found"; exit 1; } +source "$SCRIPT_DIR/lib/php-analyzer.sh" 2>/dev/null || { echo "ERROR: php-analyzer.sh not found"; exit 1; } +source "$SCRIPT_DIR/lib/system-detect.sh" 2>/dev/null || { echo "ERROR: system-detect.sh not found"; exit 1; } +source "$SCRIPT_DIR/lib/user-manager.sh" 2>/dev/null || { echo "ERROR: user-manager.sh not found"; exit 1; } + +# Color codes (using safe echo -e) +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +MAGENTA='\033[0;35m' +CYAN='\033[0;36m' +WHITE='\033[1;37m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Safe color echo function +cecho() { + echo -e "$@" +} + +# ============================================================================ +# BANNER & DISPLAY FUNCTIONS +# ============================================================================ + +show_banner() { + clear + cecho "${CYAN}╔══════════════════════════════════════════════════════════════════════╗${NC}" + cecho "${CYAN}║${WHITE} PHP & SERVER PERFORMANCE OPTIMIZER ${CYAN}║${NC}" + cecho "${CYAN}╚══════════════════════════════════════════════════════════════════════╝${NC}" + echo "" +} + +show_main_menu() { + cecho "${WHITE}${BOLD}MAIN MENU${NC}" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + echo "" + cecho " ${GREEN}1${NC}) Analyze Single Domain" + cecho " ${GREEN}2${NC}) Analyze All Domains (Server-Wide)" + cecho " ${GREEN}3${NC}) Quick Health Check (All Domains)" + cecho " ${GREEN}4${NC}) Optimize Domain PHP Settings" + cecho " ${GREEN}5${NC}) Optimize Server-Wide PHP Settings" + cecho " ${GREEN}6${NC}) View OPcache Statistics" + cecho " ${GREEN}7${NC}) View PHP-FPM Process Stats" + cecho " ${GREEN}8${NC}) Check for Configuration Issues" + echo "" + cecho " ${YELLOW}b${NC}) Backup Current Configurations" + cecho " ${YELLOW}r${NC}) Restore from Backup" + echo "" + cecho " ${RED}q${NC}) Quit" + echo "" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" +} + +# ============================================================================ +# DOMAIN SELECTION +# ============================================================================ + +select_domain() { + local action="${1:-analyze}" + + cecho "${WHITE}${BOLD}SELECT DOMAIN${NC}" + echo "" + + # Get all users with domains + local users + users=$(list_all_users) + + if [ -z "$users" ]; then + cecho "${RED}ERROR: No users found on system${NC}" + read -p "Press Enter to continue..." + return 1 + fi + + # Build domain list + declare -a domains + declare -A domain_to_user + + while IFS= read -r username; do + local user_domains + user_domains=$(get_user_domains "$username") + + while IFS= read -r domain; do + [ -z "$domain" ] && continue + domains+=("$domain") + domain_to_user["$domain"]="$username" + done <<< "$user_domains" + done <<< "$users" + + if [ ${#domains[@]} -eq 0 ]; then + cecho "${RED}ERROR: No domains found on system${NC}" + read -p "Press Enter to continue..." + return 1 + fi + + # Display numbered list + cecho "${CYAN}Available domains:${NC}" + echo "" + + local index=1 + for domain in "${domains[@]}"; do + local username="${domain_to_user[$domain]}" + local php_version + php_version=$(detect_php_version_for_domain "$domain" 2>/dev/null || echo "unknown") + + printf " ${GREEN}%-3d${NC}) %-40s ${CYAN}[${username}]${NC} ${YELLOW}(${php_version})${NC}\n" "$index" "$domain" + index=$((index + 1)) + done + + echo "" + read -p "Select domain number (or 'q' to cancel): " selection + + if [[ "$selection" == "q" ]]; then + return 1 + fi + + if ! [[ "$selection" =~ ^[0-9]+$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt ${#domains[@]} ]; then + cecho "${RED}Invalid selection${NC}" + sleep 2 + return 1 + fi + + # Return selected domain and username + local selected_domain="${domains[$((selection - 1))]}" + local selected_user="${domain_to_user[$selected_domain]}" + + echo "$selected_domain|$selected_user" + return 0 +} + +# ============================================================================ +# OPTION 1: ANALYZE SINGLE DOMAIN +# ============================================================================ + +analyze_single_domain() { + show_banner + + local selection + selection=$(select_domain "analyze") + + if [ $? -ne 0 ] || [ -z "$selection" ]; then + return + fi + + local domain username + domain=$(echo "$selection" | cut -d'|' -f1) + username=$(echo "$selection" | cut -d'|' -f2) + + show_banner + cecho "${WHITE}${BOLD}Analyzing: ${GREEN}$domain${WHITE} (user: ${CYAN}$username${WHITE})${NC}" + echo "" + + # Run comprehensive analysis + analyze_domain_php "$username" "$domain" + + echo "" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 2: ANALYZE ALL DOMAINS +# ============================================================================ + +analyze_all_domains() { + show_banner + cecho "${WHITE}${BOLD}SERVER-WIDE ANALYSIS${NC}" + echo "" + cecho "${YELLOW}This will analyze PHP configuration for ALL domains...${NC}" + echo "" + read -p "Continue? (y/n): " confirm + + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + return + fi + + show_banner + cecho "${WHITE}${BOLD}Analyzing all domains...${NC}" + echo "" + + # Get all users + local users + users=$(list_all_users) + + local total_domains=0 + local domains_with_issues=0 + + while IFS= read -r username; do + local user_domains + user_domains=$(get_user_domains "$username") + + while IFS= read -r domain; do + [ -z "$domain" ] && continue + + total_domains=$((total_domains + 1)) + + cecho "${CYAN}[$total_domains] Analyzing: ${WHITE}$domain${NC}" + + # Detect issues + local issues + issues=$(detect_php_config_issues "$username" "$domain") + + # Count critical/high severity issues + local critical_count + critical_count=$(echo "$issues" | grep -c "CRITICAL\|HIGH" || echo "0") + + if [ "$critical_count" -gt 0 ]; then + domains_with_issues=$((domains_with_issues + 1)) + cecho " ${RED}✗ $critical_count critical/high severity issues detected${NC}" + + # Show issues + while IFS='|' read -r issue_type severity message recommendation; do + [ -z "$issue_type" ] && continue + + if [[ "$severity" == "CRITICAL" ]] || [[ "$severity" == "HIGH" ]]; then + cecho " ${RED}[$severity]${NC} $issue_type: $message" + fi + done <<< "$issues" + else + cecho " ${GREEN}✓ No critical issues${NC}" + fi + + echo "" + done <<< "$user_domains" + done <<< "$users" + + # Summary + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + cecho "${WHITE}${BOLD}SUMMARY${NC}" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + cecho " Total domains analyzed: ${WHITE}$total_domains${NC}" + cecho " Domains with issues: ${RED}$domains_with_issues${NC}" + cecho " Domains healthy: ${GREEN}$((total_domains - domains_with_issues))${NC}" + echo "" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 3: QUICK HEALTH CHECK +# ============================================================================ + +quick_health_check() { + show_banner + cecho "${WHITE}${BOLD}QUICK HEALTH CHECK${NC}" + echo "" + + # Get all users + local users + users=$(list_all_users) + + declare -A issue_counts + issue_counts["CRITICAL"]=0 + issue_counts["HIGH"]=0 + issue_counts["MEDIUM"]=0 + issue_counts["LOW"]=0 + + local total_domains=0 + + while IFS= read -r username; do + local user_domains + user_domains=$(get_user_domains "$username") + + while IFS= read -r domain; do + [ -z "$domain" ] && continue + + total_domains=$((total_domains + 1)) + + # Detect issues + local issues + issues=$(detect_php_config_issues "$username" "$domain") + + # Count by severity + while IFS='|' read -r issue_type severity message recommendation; do + [ -z "$severity" ] && continue + + issue_counts["$severity"]=$((issue_counts["$severity"] + 1)) + done <<< "$issues" + done <<< "$user_domains" + done <<< "$users" + + # Display results + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + cecho "${WHITE}${BOLD}HEALTH CHECK RESULTS${NC}" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + cecho " Total Domains: ${WHITE}$total_domains${NC}" + echo "" + cecho " ${RED}CRITICAL${NC} issues: ${issue_counts["CRITICAL"]}" + cecho " ${YELLOW}HIGH${NC} issues: ${issue_counts["HIGH"]}" + cecho " ${BLUE}MEDIUM${NC} issues: ${issue_counts["MEDIUM"]}" + cecho " ${GREEN}LOW${NC} issues: ${issue_counts["LOW"]}" + echo "" + + # Overall health score + local health_score + health_score=$((100 - (issue_counts["CRITICAL"] * 20) - (issue_counts["HIGH"] * 10) - (issue_counts["MEDIUM"] * 5) - (issue_counts["LOW"] * 2))) + [ "$health_score" -lt 0 ] && health_score=0 + + if [ "$health_score" -ge 90 ]; then + cecho " Overall Health: ${GREEN}${BOLD}$health_score/100 - EXCELLENT${NC}" + elif [ "$health_score" -ge 70 ]; then + cecho " Overall Health: ${YELLOW}${BOLD}$health_score/100 - GOOD${NC}" + elif [ "$health_score" -ge 50 ]; then + cecho " Overall Health: ${YELLOW}${BOLD}$health_score/100 - FAIR${NC}" + else + cecho " Overall Health: ${RED}${BOLD}$health_score/100 - POOR${NC}" + fi + + echo "" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 4: OPTIMIZE DOMAIN +# ============================================================================ + +optimize_domain() { + show_banner + + local selection + selection=$(select_domain "optimize") + + if [ $? -ne 0 ] || [ -z "$selection" ]; then + return + fi + + local domain username + domain=$(echo "$selection" | cut -d'|' -f1) + username=$(echo "$selection" | cut -d'|' -f2) + + show_banner + cecho "${WHITE}${BOLD}OPTIMIZE: ${GREEN}$domain${NC}" + echo "" + + # Detect issues + cecho "${YELLOW}Detecting issues...${NC}" + local issues + issues=$(detect_php_config_issues "$username" "$domain") + + # Display issues + local has_issues=false + while IFS='|' read -r issue_type severity message recommendation; do + [ -z "$issue_type" ] && continue + + if [ "$issue_type" != "NONE" ]; then + has_issues=true + + case "$severity" in + CRITICAL) + cecho "${RED}[CRITICAL]${NC} $message" + ;; + HIGH) + cecho "${YELLOW}[HIGH]${NC} $message" + ;; + MEDIUM) + cecho "${BLUE}[MEDIUM]${NC} $message" + ;; + LOW) + cecho "${GREEN}[LOW]${NC} $message" + ;; + esac + + cecho " ${CYAN}→${NC} $recommendation" + echo "" + fi + done <<< "$issues" + + if [ "$has_issues" = false ]; then + cecho "${GREEN}${BOLD}✓ No issues detected - configuration is optimal!${NC}" + echo "" + read -p "Press Enter to continue..." + return + fi + + # Get optimization recommendations + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + cecho "${WHITE}${BOLD}RECOMMENDED OPTIMIZATIONS${NC}" + echo "" + + # Calculate optimal max_children + local optimal_result + optimal_result=$(calculate_optimal_max_children "$username" 1024) + local recommended_max_children reason + recommended_max_children=$(echo "$optimal_result" | cut -d'|' -f1) + reason=$(echo "$optimal_result" | cut -d'|' -f2) + + # Get current max_children + local pool_config + pool_config=$(find_fpm_pool_config "$username") + + if [ -n "$pool_config" ] && [ -f "$pool_config" ]; then + local current_max_children + current_max_children=$(grep "^pm.max_children" "$pool_config" | awk -F'=' '{print $2}' | tr -d ' ') + + if [ -n "$current_max_children" ] && [ "$recommended_max_children" -ne "$current_max_children" ]; then + cecho "${GREEN}1.${NC} Adjust ${BOLD}pm.max_children${NC} from ${RED}$current_max_children${NC} to ${GREEN}$recommended_max_children${NC}" + cecho " Reason: $reason" + echo "" + fi + fi + + # Check OPcache + local opcache_status + opcache_status=$(analyze_opcache_effectiveness "$username") + local status hit_rate opcache_rec + status=$(echo "$opcache_status" | cut -d'|' -f1) + hit_rate=$(echo "$opcache_status" | cut -d'|' -f2) + opcache_rec=$(echo "$opcache_status" | cut -d'|' -f5) + + if [ "$status" = "DISABLED" ]; then + cecho "${GREEN}2.${NC} ${BOLD}Enable OPcache${NC} for 40-70% performance boost" + echo "" + elif (( $(echo "$hit_rate < 90" | bc -l 2>/dev/null || echo "0") )); then + cecho "${GREEN}2.${NC} ${BOLD}Increase opcache.memory_consumption${NC} (current hit rate: ${hit_rate}%)" + echo "" + fi + + echo "" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + cecho "${YELLOW}${BOLD}WARNING:${NC} ${YELLOW}Automatic optimization not yet implemented${NC}" + cecho "${YELLOW}Please apply the above recommendations manually${NC}" + echo "" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 6: VIEW OPCACHE STATISTICS +# ============================================================================ + +view_opcache_stats() { + show_banner + + local selection + selection=$(select_domain "opcache") + + if [ $? -ne 0 ] || [ -z "$selection" ]; then + return + fi + + local domain username + domain=$(echo "$selection" | cut -d'|' -f1) + username=$(echo "$selection" | cut -d'|' -f2) + + show_banner + cecho "${WHITE}${BOLD}OPCACHE STATISTICS: ${GREEN}$domain${NC}" + echo "" + + # Get OPcache stats + local stats + stats=$(get_opcache_stats "$username") + + if [ -z "$stats" ]; then + cecho "${RED}Unable to retrieve OPcache statistics${NC}" + echo "" + read -p "Press Enter to continue..." + return + fi + + # Parse and display + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + cecho "${WHITE}${BOLD}OPCACHE STATUS${NC}" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + + local enabled + enabled=$(check_opcache_enabled "$username") + + if [ "$enabled" = "1" ]; then + cecho " Status: ${GREEN}ENABLED${NC}" + else + cecho " Status: ${RED}DISABLED${NC}" + echo "" + read -p "Press Enter to continue..." + return + fi + + # Display stats + while IFS='=' read -r key value; do + [ -z "$key" ] && continue + + case "$key" in + memory_usage_mb) + cecho " Memory Used: ${WHITE}${value}MB${NC}" + ;; + hits) + cecho " Cache Hits: ${GREEN}$value${NC}" + ;; + misses) + cecho " Cache Misses: ${YELLOW}$value${NC}" + ;; + num_cached_scripts) + cecho " Cached Scripts: ${WHITE}$value${NC}" + ;; + max_cached_keys) + cecho " Max Cached Keys: ${WHITE}$value${NC}" + ;; + wasted_memory_mb) + cecho " Wasted Memory: ${RED}${value}MB${NC}" + ;; + esac + done <<< "$stats" + + # Calculate and display hit rate + local hit_rate + hit_rate=$(calculate_opcache_hit_rate "$username") + echo "" + cecho " Hit Rate: ${GREEN}${BOLD}${hit_rate}%${NC}" + + # Recommendation + echo "" + if (( $(echo "$hit_rate < 90" | bc -l 2>/dev/null || echo "0") )); then + cecho " ${YELLOW}⚠ Hit rate below 90% - Consider increasing opcache.memory_consumption${NC}" + else + cecho " ${GREEN}✓ Hit rate is excellent${NC}" + fi + + echo "" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 7: VIEW PHP-FPM PROCESS STATS +# ============================================================================ + +view_fpm_stats() { + show_banner + + local selection + selection=$(select_domain "fpm") + + if [ $? -ne 0 ] || [ -z "$selection" ]; then + return + fi + + local domain username + domain=$(echo "$selection" | cut -d'|' -f1) + username=$(echo "$selection" | cut -d'|' -f2) + + show_banner + cecho "${WHITE}${BOLD}PHP-FPM PROCESS STATISTICS: ${GREEN}$domain${NC}" + echo "" + + # Get process stats + local memory_stats + memory_stats=$(calculate_memory_per_process "$username") + + local avg_kb process_count total_mb + avg_kb=$(echo "$memory_stats" | cut -d'|' -f1) + process_count=$(echo "$memory_stats" | cut -d'|' -f2) + total_mb=$(echo "$memory_stats" | cut -d'|' -f3) + + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + cecho "${WHITE}${BOLD}CURRENT RESOURCE USAGE${NC}" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + echo "" + + if [ "$process_count" -eq 0 ]; then + cecho "${YELLOW}No active PHP-FPM processes found${NC}" + echo "" + read -p "Press Enter to continue..." + return + fi + + cecho " Active Processes: ${WHITE}$process_count${NC}" + cecho " Avg Memory/Process: ${WHITE}$((avg_kb / 1024))MB${NC} (${avg_kb}KB)" + cecho " Total Memory: ${WHITE}${total_mb}MB${NC}" + echo "" + + # Get pool config + local pool_config + pool_config=$(find_fpm_pool_config "$username") + + if [ -n "$pool_config" ] && [ -f "$pool_config" ]; then + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + cecho "${WHITE}${BOLD}POOL CONFIGURATION${NC}" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + echo "" + + local pool_settings + pool_settings=$(parse_fpm_pool_config "$pool_config") + + # Display key settings + while IFS='=' read -r key value; do + [ -z "$key" ] && continue + cecho " $key: ${WHITE}$value${NC}" + done <<< "$pool_settings" + fi + + # Calculate optimal max_children + echo "" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + cecho "${WHITE}${BOLD}RECOMMENDATION${NC}" + cecho "${CYAN}─────────────────────────────────────────────────────────────────────${NC}" + echo "" + + local optimal_result + optimal_result=$(calculate_optimal_max_children "$username" 1024) + local recommended reason + recommended=$(echo "$optimal_result" | cut -d'|' -f1) + reason=$(echo "$optimal_result" | cut -d'|' -f2) + + cecho " Optimal pm.max_children: ${GREEN}${BOLD}$recommended${NC}" + cecho " Reason: $reason" + + echo "" + cecho "${CYAN}═══════════════════════════════════════════════════════════════════${NC}" + read -p "Press Enter to continue..." +} + +# ============================================================================ +# OPTION 8: CHECK FOR ISSUES +# ============================================================================ + +check_config_issues() { + show_banner + + local selection + selection=$(select_domain "check") + + if [ $? -ne 0 ] || [ -z "$selection" ]; then + return + fi + + local domain username + domain=$(echo "$selection" | cut -d'|' -f1) + username=$(echo "$selection" | cut -d'|' -f2) + + show_banner + cecho "${WHITE}${BOLD}CONFIGURATION ISSUES: ${GREEN}$domain${NC}" + echo "" + + # Detect issues + local issues + issues=$(detect_php_config_issues "$username" "$domain") + + # Display by severity + local has_critical=false + local has_high=false + local has_medium=false + local has_low=false + + # Check for each severity level + echo "$issues" | grep -q "CRITICAL" && has_critical=true + echo "$issues" | grep -q "HIGH" && has_high=true + echo "$issues" | grep -q "MEDIUM" && has_medium=true + echo "$issues" | grep -q "LOW" && has_low=true + + # Display CRITICAL + if [ "$has_critical" = true ]; then + cecho "${RED}${BOLD}CRITICAL ISSUES:${NC}" + echo "" + + while IFS='|' read -r issue_type severity message recommendation; do + [ "$severity" != "CRITICAL" ] && continue + + cecho " ${RED}●${NC} $message" + cecho " ${CYAN}→${NC} $recommendation" + echo "" + done <<< "$issues" + fi + + # Display HIGH + if [ "$has_high" = true ]; then + cecho "${YELLOW}${BOLD}HIGH PRIORITY ISSUES:${NC}" + echo "" + + while IFS='|' read -r issue_type severity message recommendation; do + [ "$severity" != "HIGH" ] && continue + + cecho " ${YELLOW}●${NC} $message" + cecho " ${CYAN}→${NC} $recommendation" + echo "" + done <<< "$issues" + fi + + # Display MEDIUM + if [ "$has_medium" = true ]; then + cecho "${BLUE}${BOLD}MEDIUM PRIORITY ISSUES:${NC}" + echo "" + + while IFS='|' read -r issue_type severity message recommendation; do + [ "$severity" != "MEDIUM" ] && continue + + cecho " ${BLUE}●${NC} $message" + cecho " ${CYAN}→${NC} $recommendation" + echo "" + done <<< "$issues" + fi + + # Display LOW + if [ "$has_low" = true ]; then + cecho "${GREEN}${BOLD}LOW PRIORITY ISSUES:${NC}" + echo "" + + while IFS='|' read -r issue_type severity message recommendation; do + [ "$severity" != "LOW" ] && continue + + cecho " ${GREEN}●${NC} $message" + cecho " ${CYAN}→${NC} $recommendation" + echo "" + done <<< "$issues" + fi + + # No issues + if [ "$has_critical" = false ] && [ "$has_high" = false ] && [ "$has_medium" = false ] && [ "$has_low" = false ]; then + cecho "${GREEN}${BOLD}✓ No configuration issues detected!${NC}" + cecho "${GREEN}Configuration appears to be optimal.${NC}" + echo "" + fi + + read -p "Press Enter to continue..." +} + +# ============================================================================ +# MAIN LOOP +# ============================================================================ + +main() { + # Detect system + detect_system + + # Check if running as root + if [ "$EUID" -ne 0 ]; then + cecho "${RED}ERROR: This script must be run as root${NC}" + exit 1 + fi + + # Check for PHP-FPM + if ! is_using_php_fpm; then + cecho "${YELLOW}WARNING: PHP-FPM not detected. Some features may not work.${NC}" + read -p "Press Enter to continue anyway..." + fi + + # Main loop + while true; do + show_banner + show_main_menu + + read -p "Select option: " choice + + case "$choice" in + 1) + analyze_single_domain + ;; + 2) + analyze_all_domains + ;; + 3) + quick_health_check + ;; + 4) + optimize_domain + ;; + 5) + cecho "${YELLOW}Server-wide optimization not yet implemented${NC}" + sleep 2 + ;; + 6) + view_opcache_stats + ;; + 7) + view_fpm_stats + ;; + 8) + check_config_issues + ;; + b) + cecho "${YELLOW}Backup feature not yet implemented${NC}" + sleep 2 + ;; + r) + cecho "${YELLOW}Restore feature not yet implemented${NC}" + sleep 2 + ;; + q|Q) + cecho "${GREEN}Exiting PHP Optimizer...${NC}" + exit 0 + ;; + *) + cecho "${RED}Invalid option${NC}" + sleep 1 + ;; + esac + done +} + +# Run main +main "$@"