From 9b7cdc704d1d771ebc1558a227fe150673c12ae4 Mon Sep 17 00:00:00 2001 From: cschantz Date: Mon, 3 Nov 2025 21:00:27 -0500 Subject: [PATCH] Enhance 500 error tracker: bot filtering, comprehensive validation, specific diagnostics Major improvements to provide actionable, specific diagnostics instead of generic advice: - Add bot/scanner filtering to reduce noise (monitors, SEO tools, security scanners, HTTP clients) - Track and display filtered bot count in summary - Remove all emojis from output - Fix ANSI escape codes with echo -e for proper color rendering Comprehensive file/permission validation: - Resolve URLs to actual file paths being requested - Test .htaccess readability by Apache (nobody user) - Validate .htaccess syntax with apache2ctl -t - Detect invalid PHP directives (php_value/php_flag without mod_php) - Find malformed RewriteRule and orphaned RewriteCond - Check document root and specific file permissions - Test if files are readable by Apache user Enhanced error extraction: - Extract exact file paths from PHP errors - Get line numbers for syntax errors - Extract function names for missing function errors - Get database usernames/names from DB errors - Show current memory limits for memory exhaustion - Identify specific files with permission issues Add detailed per-URL diagnostics section: - Show domain + URL + specific issue + file path + exact problem - Group by error type with up to 20 examples per type - Examples: "example.com/wp-admin - Permission denied on: /home/user/wp-config.php (perms: 600, owner: root:root) - NOT readable by Apache" --- modules/website/500-error-tracker.sh | 375 +++++++++++++++++++++++---- 1 file changed, 324 insertions(+), 51 deletions(-) diff --git a/modules/website/500-error-tracker.sh b/modules/website/500-error-tracker.sh index 693580b..8ec02c8 100755 --- a/modules/website/500-error-tracker.sh +++ b/modules/website/500-error-tracker.sh @@ -57,6 +57,7 @@ cutoff_time=$(date -d "$HOURS_TO_SCAN hours ago" +%s 2>/dev/null || echo "0") declare -A domain_count declare -A domain_user total_500s=0 +filtered_bots=0 # Scan all domain access logs for 500 errors for log in "$DOMLOGS_DIR"/*; do @@ -80,7 +81,7 @@ for log in "$DOMLOGS_DIR"/*; do # Check for 500 status code if [[ "$line" =~ '"'[[:space:]](5[0-9]{2})[[:space:]] ]]; then status="${BASH_REMATCH[1]}" - + # Time filtering if [ "$cutoff_time" != "0" ]; then if [[ "$line" =~ \[([0-9]{2}/[A-Z][a-z]{2}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}) ]]; then @@ -89,7 +90,22 @@ for log in "$DOMLOGS_DIR"/*; do [ "$log_time" != "0" ] && [ "$log_time" -lt "$cutoff_time" ] && continue fi fi - + + # Bot/Scanner filtering - skip noise + line_lower="${line,,}" + if [[ "$line_lower" =~ (bot|crawler|spider|scraper|scanner|check|monitor|uptime|pingdom|newrelic|datadog|nagios|zabbix|prtg|gomez|keynote|catchpoint|dotcom-monitor|site24x7|uptimerobot|statuscake|nodequery|hetrixtools|freshping|uptrendscom|siteuptime|montastic|updown\.io|apex|alertsite|webmon|wormly) ]]; then + ((filtered_bots++)) + continue + fi + if [[ "$line_lower" =~ (semrush|ahrefs|moz|majestic|serpstat|screaming|screamingfrog|sitebulb|linkchecker|validator|scanner|security|acunetix|nessus|openvas|burp|nikto|skipfish|w3af|sqlmap|metasploit|nmap|masscan|zmap|shodan|censys|binaryedge) ]]; then + ((filtered_bots++)) + continue + fi + if [[ "$line_lower" =~ (curl|wget|python|perl|ruby|java|go-http|libwww|axios|node-fetch|http\.client|httpie|postman|insomnia|apachehttp|okhttp|httpclient) ]]; then + ((filtered_bots++)) + continue + fi + # Parse log line read -r ip _ _ timestamp _ request _ _ <<< "$line" @@ -126,7 +142,7 @@ if [ "$total_500s" -eq 0 ]; then fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " 🔥 500 ERRORS DETECTED: $total_500s errors" +echo " 500 ERRORS DETECTED: $total_500s errors (filtered out $filtered_bots bot/scanner requests)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" @@ -142,21 +158,52 @@ done echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " 🔍 DIAGNOSING ROOT CAUSES" +echo " DIAGNOSING ROOT CAUSES" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" -# For each affected domain, check the actual PHP error logs +# Detailed diagnostic tracking - per URL/file +DETAILED_DIAGNOSIS="$TEMP_DIR/detailed_diagnosis.txt" +> "$DETAILED_DIAGNOSIS" + declare -A diagnosed_causes declare -A cause_examples while IFS='|' read -r domain user status url timestamp ip; do [ -z "$domain" ] && continue + diagnosis="" + cause="UNKNOWN" + specific_file="" + + # Get document root + docroot="/home/$user/public_html" + + # Try to determine the actual file being requested + if [[ "$url" =~ ^/([^?]+) ]]; then + url_path="${BASH_REMATCH[1]}" + + # Handle common patterns + if [ -z "$url_path" ] || [ "$url_path" = "/" ]; then + possible_files=("$docroot/index.php" "$docroot/index.html") + elif [[ "$url_path" =~ \.php$ ]]; then + possible_files=("$docroot/$url_path") + else + possible_files=("$docroot/$url_path" "$docroot/${url_path}.php" "$docroot/$url_path/index.php") + fi + + # Find the actual file + for pf in "${possible_files[@]}"; do + if [ -f "$pf" ]; then + specific_file="$pf" + break + fi + done + fi + # Find PHP error log - check multiple locations error_log="" if [ "$user" != "unknown" ]; then - # Try multiple possible locations for potential_log in \ "/home/$user/public_html/error_log" \ "/home/$user/logs/error_log" \ @@ -173,51 +220,245 @@ while IFS='|' read -r domain user status url timestamp ip; do # Check if error log exists and has recent errors if [ -n "$error_log" ] && [ -f "$error_log" ]; then - # Look for errors around the same time as the 500 - recent_error=$(tail -500 "$error_log" | grep -E "Fatal error|Parse error|syntax error|memory.*exhausted|database|MySQL|Permission denied" | tail -1) + # Look for errors matching this URL/timestamp + recent_error=$(tail -1000 "$error_log" | grep -F "$url" | tail -1) + + # If no URL match, get most recent error + [ -z "$recent_error" ] && recent_error=$(tail -500 "$error_log" | grep -E "Fatal error|Parse error|syntax error|memory.*exhausted|database|MySQL|Permission denied|failed to open stream" | tail -1) if [ -n "$recent_error" ]; then - # Determine cause - cause="UNKNOWN" + # Extract file path from error if present + if [[ "$recent_error" =~ in[[:space:]](/[^:]+\.php) ]]; then + error_file="${BASH_REMATCH[1]}" + specific_file="$error_file" + fi + + # Determine cause and diagnose if [[ "$recent_error" =~ (memory.*exhausted|Allowed memory size) ]]; then cause="PHP_MEMORY_EXHAUSTED" - cause_examples["$cause"]="$domain: $recent_error" + + # Check current memory limit + mem_limit=$(grep -h "memory_limit" "$docroot/.user.ini" "$docroot/../.php.ini" 2>/dev/null | tail -1 | cut -d'=' -f2 | tr -d ' ') + [ -z "$mem_limit" ] && mem_limit=$(php -r "echo ini_get('memory_limit');" 2>/dev/null) + + diagnosis="$domain$url - Memory exhausted (current limit: ${mem_limit:-unknown})" + [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file" + + elif [[ "$recent_error" =~ (failed to open stream|Permission denied) ]]; then + cause="PERMISSION_ERROR" + + # Extract the file with permission issue + if [[ "$recent_error" =~ failed\ to\ open\ stream.*\'([^\']+)\' ]]; then + perm_file="${BASH_REMATCH[1]}" + elif [[ "$recent_error" =~ Permission\ denied.*\'([^\']+)\' ]]; then + perm_file="${BASH_REMATCH[1]}" + else + perm_file="$specific_file" + fi + + # Check permissions on that specific file + if [ -n "$perm_file" ] && [ -e "$perm_file" ]; then + file_perms=$(stat -c "%a" "$perm_file" 2>/dev/null) + file_owner=$(stat -c "%U:%G" "$perm_file" 2>/dev/null) + diagnosis="$domain$url - Permission denied on: $perm_file (perms: $file_perms, owner: $file_owner)" + + # Check if file is readable by Apache + if [ -f "$perm_file" ]; then + if ! sudo -u nobody test -r "$perm_file" 2>/dev/null; then + diagnosis="$diagnosis - File NOT readable by Apache (nobody user)" + fi + fi + else + diagnosis="$domain$url - Permission denied (file in error: $perm_file - does not exist)" + fi + elif [[ "$recent_error" =~ (Fatal error|PHP Fatal error) ]]; then if [[ "$recent_error" =~ (undefined function|Call to undefined function) ]]; then cause="MISSING_PHP_FUNCTION" - cause_examples["$cause"]="$domain: $recent_error" + + # Extract function name + if [[ "$recent_error" =~ Call\ to\ undefined\ function\ ([a-zA-Z0-9_]+) ]]; then + missing_func="${BASH_REMATCH[1]}" + + # Check which extension provides this function + ext_info=$(php -r "if(function_exists('$missing_func')) echo 'EXISTS'; else echo 'MISSING';" 2>&1) + + diagnosis="$domain$url - Missing function: $missing_func" + [ -n "$specific_file" ] && diagnosis="$diagnosis - in file: $specific_file" + else + diagnosis="$domain$url - Missing PHP function - $recent_error" + fi else cause="PHP_FATAL_ERROR" - cause_examples["$cause"]="$domain: $recent_error" + diagnosis="$domain$url - PHP Fatal Error" + [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file" + diagnosis="$diagnosis - ${recent_error:0:200}" fi + elif [[ "$recent_error" =~ (Parse error|syntax error) ]]; then cause="PHP_SYNTAX_ERROR" - cause_examples["$cause"]="$domain: $recent_error" - elif [[ "$recent_error" =~ (database|MySQL|Can\'t connect) ]]; then + + # Extract line number if present + if [[ "$recent_error" =~ line\ ([0-9]+) ]]; then + error_line="${BASH_REMATCH[1]}" + diagnosis="$domain$url - PHP Syntax Error at line $error_line" + else + diagnosis="$domain$url - PHP Syntax Error" + fi + [ -n "$specific_file" ] && diagnosis="$diagnosis - File: $specific_file" + + elif [[ "$recent_error" =~ (database|MySQL|Can\'t connect|Access denied for user) ]]; then cause="DATABASE_CONNECTION" - cause_examples["$cause"]="$domain: $recent_error" + + if [[ "$recent_error" =~ Access\ denied\ for\ user\ \'([^\']+)\' ]]; then + db_user="${BASH_REMATCH[1]}" + diagnosis="$domain$url - Database access denied for user: $db_user" + elif [[ "$recent_error" =~ Unknown\ database\ \'([^\']+)\' ]]; then + db_name="${BASH_REMATCH[1]}" + diagnosis="$domain$url - Unknown database: $db_name" + else + diagnosis="$domain$url - Database connection error" + fi + [ -n "$specific_file" ] && diagnosis="$diagnosis - from file: $specific_file" fi - + + # Save detailed diagnosis + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" else ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++)) fi else - # No error log found - likely .htaccess issue - # Check if .htaccess exists and might have issues - if [ "$user" != "unknown" ] && [ -f "/home/$user/public_html/.htaccess" ]; then - # Check for common .htaccess syntax errors - htaccess_check=$(grep -E "RewriteEngine|RewriteRule|RewriteCond|php_value|php_flag" "/home/$user/public_html/.htaccess" 2>/dev/null) - if [ -n "$htaccess_check" ]; then - ((diagnosed_causes["HTACCESS_LIKELY"]++)) - cause_examples["HTACCESS_LIKELY"]="$domain (user: $user) - has .htaccess with rewrite rules, check syntax" + # No error log found - check .htaccess and permissions thoroughly + if [ "$user" != "unknown" ]; then + htaccess_file="$docroot/.htaccess" + + if [ -f "$htaccess_file" ]; then + # Check .htaccess file permissions first + htaccess_perms=$(stat -c "%a" "$htaccess_file" 2>/dev/null) + htaccess_owner=$(stat -c "%U:%G" "$htaccess_file" 2>/dev/null) + + # Check if readable by Apache + htaccess_readable="yes" + if ! sudo -u nobody test -r "$htaccess_file" 2>/dev/null; then + htaccess_readable="no" + fi + + # Actually validate .htaccess syntax + htaccess_test=$(apache2ctl -t 2>&1) + htaccess_issues="" + + # Check for invalid directives + if grep -qE "^[[:space:]]*(php_value|php_flag|php_admin_value|php_admin_flag)" "$htaccess_file" 2>/dev/null; then + if ! apache2ctl -M 2>/dev/null | grep -q "php.*module"; then + htaccess_issues="PHP directives (php_value/php_flag) incompatible with current PHP handler (not mod_php)" + fi + fi + + # Check for malformed RewriteRule + bad_rewrite=$(grep -nE "RewriteRule.*\[.*[^]]*$" "$htaccess_file" 2>/dev/null | head -1) + if [ -n "$bad_rewrite" ]; then + htaccess_issues="${htaccess_issues:+$htaccess_issues; }Malformed RewriteRule: $bad_rewrite" + fi + + # Check for RewriteCond without following RewriteRule + orphan_cond=$(grep -n "RewriteCond" "$htaccess_file" | while read line; do + linenum=$(echo "$line" | cut -d: -f1) + nextline=$((linenum + 1)) + next=$(sed -n "${nextline}p" "$htaccess_file") + if [[ ! "$next" =~ RewriteRule|RewriteCond ]]; then + echo "Line $linenum: RewriteCond without RewriteRule" + fi + done | head -1) + + if [ -n "$orphan_cond" ]; then + htaccess_issues="${htaccess_issues:+$htaccess_issues; }$orphan_cond" + fi + + # Check for syntax errors in .htaccess + if echo "$htaccess_test" | grep -qi "syntax error"; then + syntax_err=$(echo "$htaccess_test" | grep -i "syntax error" | head -1) + htaccess_issues="${htaccess_issues:+$htaccess_issues; }Apache syntax error: $syntax_err" + fi + + if [ "$htaccess_readable" = "no" ]; then + cause="PERMISSION_ERROR" + diagnosis="$domain$url - .htaccess not readable by Apache (perms: $htaccess_perms, owner: $htaccess_owner)" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + elif [ -n "$htaccess_issues" ]; then + cause="HTACCESS_ERROR" + diagnosis="$domain$url - .htaccess error: $htaccess_issues" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + else + # .htaccess appears valid - check document root and file permissions + docroot_perms=$(stat -c "%a" "$docroot" 2>/dev/null) + docroot_owner=$(stat -c "%U:%G" "$docroot" 2>/dev/null) + + if [ "$docroot_perms" != "755" ] && [ "$docroot_perms" != "750" ]; then + cause="PERMISSION_ERROR" + diagnosis="$domain$url - Document root incorrect permissions (perms: $docroot_perms, owner: $docroot_owner, should be 755)" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + elif [ -n "$specific_file" ] && [ -f "$specific_file" ]; then + # Check the specific PHP file permissions + file_perms=$(stat -c "%a" "$specific_file" 2>/dev/null) + file_owner=$(stat -c "%U:%G" "$specific_file" 2>/dev/null) + file_readable="yes" + + if ! sudo -u nobody test -r "$specific_file" 2>/dev/null; then + file_readable="no" + fi + + if [ "$file_readable" = "no" ]; then + cause="PERMISSION_ERROR" + diagnosis="$domain$url - File not readable by Apache: $specific_file (perms: $file_perms, owner: $file_owner)" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + else + ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++)) + fi + else + ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++)) + fi + fi else - ((diagnosed_causes["NO_ERROR_LOG_FILE"]++)) - cause_examples["NO_ERROR_LOG_FILE"]="$domain (user: $user) - checked multiple locations, no error_log found" + # No .htaccess - check document root and file permissions + docroot_perms=$(stat -c "%a" "$docroot" 2>/dev/null) + docroot_owner=$(stat -c "%U:%G" "$docroot" 2>/dev/null) + + if [ "$docroot_perms" != "755" ] && [ "$docroot_perms" != "750" ]; then + cause="PERMISSION_ERROR" + diagnosis="$domain$url - Document root incorrect permissions (perms: $docroot_perms, owner: $docroot_owner, should be 755)" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + elif [ -n "$specific_file" ] && [ -f "$specific_file" ]; then + # Check the specific PHP file + file_perms=$(stat -c "%a" "$specific_file" 2>/dev/null) + file_owner=$(stat -c "%U:%G" "$specific_file" 2>/dev/null) + + if ! sudo -u nobody test -r "$specific_file" 2>/dev/null; then + cause="PERMISSION_ERROR" + diagnosis="$domain$url - File not readable: $specific_file (perms: $file_perms, owner: $file_owner)" + echo "$cause|$diagnosis" >> "$DETAILED_DIAGNOSIS" + ((diagnosed_causes["$cause"]++)) + [ -z "${cause_examples[$cause]}" ] && cause_examples["$cause"]="$diagnosis" + else + ((diagnosed_causes["NO_ERROR_LOG_FILE"]++)) + fi + else + ((diagnosed_causes["NO_ERROR_LOG_FILE"]++)) + fi fi else ((diagnosed_causes["NO_ERROR_LOG_FILE"]++)) - cause_examples["NO_ERROR_LOG_FILE"]="$domain (user: $user) - checked multiple locations, no error_log found" fi fi done < "$ERRORS_500" @@ -234,43 +475,43 @@ done | sort -rn | while IFS='|' read count cause; do case "$cause" in PHP_MEMORY_EXHAUSTED) - echo -e "${RED}🔥 $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Increase memory_limit in /home/USER/public_html/.user.ini" - echo " ${YELLOW}Set:${NC} memory_limit = 512M" + echo -e "${RED}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Fix:${NC} Increase memory_limit in /home/USER/public_html/.user.ini" + echo -e " ${YELLOW}Set:${NC} memory_limit = 512M" ;; PHP_FATAL_ERROR) - echo -e "${RED}⚠️ $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Review recent code/plugin changes" + echo -e "${RED}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Fix:${NC} Review recent code/plugin changes" ;; PHP_SYNTAX_ERROR) - echo -e "${RED}📝 $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Check for PHP syntax errors in recent file edits" + echo -e "${RED}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Fix:${NC} Check for PHP syntax errors in recent file edits" ;; MISSING_PHP_FUNCTION) - echo -e "${RED}📦 $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Install missing PHP extension (check error for which one)" + echo -e "${RED}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Fix:${NC} Install missing PHP extension (check error for which one)" ;; DATABASE_CONNECTION) - echo -e "${RED}🗄️ $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Check database credentials or MySQL service" + echo -e "${RED}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Fix:${NC} Check database credentials or MySQL service" ;; - HTACCESS_LIKELY) - echo -e "${RED}⚙️ .HTACCESS SYNTAX ERROR (LIKELY)${NC} - $count occurrences" - echo " ${YELLOW}Fix:${NC} Check .htaccess file for syntax errors" - echo " ${YELLOW}Test:${NC} Temporarily rename .htaccess to .htaccess.bak and test" - echo " ${YELLOW}Common issues:${NC} Invalid RewriteRule, bad php_value directives" + HTACCESS_ERROR) + echo -e "${RED}.HTACCESS ERROR DETECTED${NC} - $count occurrences" + ;; + PERMISSION_ERROR) + echo -e "${RED}PERMISSION ERROR DETECTED${NC} - $count occurrences" ;; NO_ERROR_LOG_FILE) - echo -e "${YELLOW}📄 $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Note:${NC} Checked multiple error_log locations - none found" - echo " ${YELLOW}Check:${NC} May need to enable PHP error logging" + echo -e "${YELLOW}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Note:${NC} Checked multiple error_log locations - none found" + echo -e " ${YELLOW}Check:${NC} May need to enable PHP error logging" ;; NO_PHP_ERROR_LOGGED) - echo -e "${YELLOW}❓ $clean_cause${NC} - $count occurrences" - echo " ${YELLOW}Note:${NC} 500 error but no PHP error in log - likely .htaccess or Apache config" + echo -e "${YELLOW}$clean_cause${NC} - $count occurrences" + echo -e " ${YELLOW}Note:${NC} 500 error but no PHP error in log - likely .htaccess or Apache config" ;; *) - echo -e "${INFO_COLOR}• $clean_cause${NC} - $count occurrences" + echo -e "${INFO_COLOR}$clean_cause${NC} - $count occurrences" ;; esac @@ -283,7 +524,7 @@ done | sort -rn | while IFS='|' read count cause; do done echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo " 📋 DETAILED 500 ERROR LIST" +echo " DETAILED 500 ERROR LIST" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" @@ -298,7 +539,39 @@ cut -d'|' -f1,4 "$ERRORS_500" | sort | uniq -c | sort -rn | head -15 | while rea done echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " SPECIFIC DIAGNOSTICS (per URL/file)" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Show detailed diagnostics grouped by cause +if [ -f "$DETAILED_DIAGNOSIS" ] && [ -s "$DETAILED_DIAGNOSIS" ]; then + for cause_type in PHP_MEMORY_EXHAUSTED PERMISSION_ERROR HTACCESS_ERROR PHP_FATAL_ERROR PHP_SYNTAX_ERROR MISSING_PHP_FUNCTION DATABASE_CONNECTION; do + cause_count=$(grep -c "^${cause_type}|" "$DETAILED_DIAGNOSIS" 2>/dev/null || echo "0") + + if [ "$cause_count" -gt 0 ]; then + cause_display=$(echo "$cause_type" | tr '_' ' ') + echo -e "${RED}${BOLD}$cause_display ($cause_count)${NC}" + echo "" + + grep "^${cause_type}|" "$DETAILED_DIAGNOSIS" | cut -d'|' -f2 | head -20 | while read -r diag_line; do + echo -e " ${YELLOW}•${NC} $diag_line" + done + + if [ "$cause_count" -gt 20 ]; then + remaining=$((cause_count - 20)) + echo -e " ${DIM}... and $remaining more${NC}" + fi + echo "" + fi + done +else + echo "No detailed diagnostics available." + echo "" +fi + echo "Full error list saved to: $ERRORS_500" +echo "Detailed diagnostics saved to: $DETAILED_DIAGNOSIS" echo "" press_enter