22fa5ad8b0
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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
800 lines
28 KiB
Bash
Executable File
800 lines
28 KiB
Bash
Executable File
#!/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 "$@"
|