#!/bin/bash ################################################################################ # Extended Analysis Functions ################################################################################ # Purpose: All 32 additional intelligence checks for website slowness # Categories: WordPress, Database, PHP, Web Server, Cron/Tasks ################################################################################ # ============================================================================ # CATEGORY 1: WORDPRESS-SPECIFIC SETTINGS (8 checks) # ============================================================================ ### 1.1 - WP_DEBUG Enabled Check analyze_wp_debug() { local docroot="$1" local wp_config="$docroot/wp-config.php" if [ ! -f "$wp_config" ]; then return 0 fi local debug_enabled=$(grep -c "define.*'WP_DEBUG'.*true" "$wp_config" 2>/dev/null || echo 0) if [ "$debug_enabled" -gt 0 ]; then save_analysis_data "wordpress_settings.tmp" "CRITICAL: WP_DEBUG enabled in production" save_analysis_data "wordpress_settings.tmp" " Impact: 10-15% performance penalty from error logging" save_analysis_data "wordpress_settings.tmp" " Fix: Set define( 'WP_DEBUG', false );" fi } ### 1.2 - XML-RPC Enabled Check analyze_xmlrpc() { local domain="$1" local xmlrpc_test=$(curl -s -m 3 "https://$domain/xmlrpc.php" -w "%{http_code}" -o /dev/null 2>/dev/null || echo "000") if [ "$xmlrpc_test" != "403" ] && [ "$xmlrpc_test" != "404" ]; then save_analysis_data "wordpress_settings.tmp" "WARNING: XML-RPC is enabled" save_analysis_data "wordpress_settings.tmp" " Security risk, unnecessary API exposure" save_analysis_data "wordpress_settings.tmp" " Fix: Add to .htaccess or disable via plugin" fi } ### 1.3 - WordPress Heartbeat API analyze_heartbeat_api() { local docroot="$1" if [ -f "$docroot/wp-config.php" ]; then local heartbeat_interval=$(grep -o "HEARTBEAT_INTERVAL.*[0-9]*" "$docroot/wp-config.php" 2>/dev/null | grep -o "[0-9]*" | head -1) if [ -z "$heartbeat_interval" ]; then save_analysis_data "wordpress_settings.tmp" "INFO: Heartbeat running at default (15s) interval" save_analysis_data "wordpress_settings.tmp" " Recommendation: Increase to 60s: define('HEARTBEAT_INTERVAL', 60);" elif [ "$heartbeat_interval" -lt 30 ]; then save_analysis_data "wordpress_settings.tmp" "WARNING: Heartbeat interval too frequent: ${heartbeat_interval}s" save_analysis_data "wordpress_settings.tmp" " Recommend: At least 60 seconds" fi fi } ### 1.4 - Autosave Frequency analyze_autosave_frequency() { local docroot="$1" if [ -f "$docroot/wp-config.php" ]; then local autosave_interval=$(grep -o "AUTOSAVE_INTERVAL.*[0-9]*" "$docroot/wp-config.php" 2>/dev/null | grep -o "[0-9]*" | head -1) if [ -z "$autosave_interval" ] || [ "$autosave_interval" -lt 120 ]; then save_analysis_data "wordpress_settings.tmp" "INFO: Autosave frequency at default or too frequent" save_analysis_data "wordpress_settings.tmp" " Recommendation: Set to 300s (5 min): define('AUTOSAVE_INTERVAL', 300);" fi fi } ### 1.5 - REST API Exposure analyze_rest_api_exposure() { local domain="$1" local rest_test=$(curl -s -m 3 "https://$domain/wp-json/wp/v2/posts" 2>/dev/null | head -c 50) if [[ "$rest_test" == *"ID"* ]] || [[ "$rest_test" == *"title"* ]]; then save_analysis_data "wordpress_settings.tmp" "INFO: REST API is fully exposed (public)" save_analysis_data "wordpress_settings.tmp" " Consider: Require authentication or limit access" fi } ### 1.6 - Emoji Support analyze_emoji_scripts() { local domain="$1" local emoji_test=$(curl -s -m 5 "https://$domain" 2>/dev/null | grep -c "wp-emoji" || echo 0) if [ "$emoji_test" -gt 0 ]; then save_analysis_data "wordpress_settings.tmp" "INFO: Emoji support scripts loading" save_analysis_data "wordpress_settings.tmp" " Unnecessary for most sites, adds 1-2 extra HTTP requests" save_analysis_data "wordpress_settings.tmp" " Fix: Use disable-emojis plugin or add function to disable" fi } ### 1.7 - Post Revision Distribution analyze_post_revision_distribution() { local db_name="$1" if [ -z "$db_name" ]; then return 0 fi local high_revision_posts=$(mysql -Ns -e " SELECT COUNT(DISTINCT post_parent) FROM ${db_name}.wp_posts WHERE post_type='revision' GROUP BY post_parent HAVING COUNT(*) > 50; " 2>/dev/null | wc -l || echo 0) if [ "$high_revision_posts" -gt 0 ]; then save_analysis_data "wordpress_settings.tmp" "WARNING: $high_revision_posts posts with >50 revisions each" save_analysis_data "wordpress_settings.tmp" " These posts bloat the database" save_analysis_data "wordpress_settings.tmp" " Fix: Delete old revisions: wp post delete \$(wp post list --format=ids --post_type=revision) --force" fi } ### 1.8 - Pingbacks/Trackbacks analyze_pingbacks_trackbacks() { local docroot="$1" if [ -f "$docroot/wp-config.php" ]; then # Check if default setting is configured if ! grep -q "default_ping_status" "$docroot/wp-config.php"; then save_analysis_data "wordpress_settings.tmp" "INFO: Pingbacks/trackbacks enabled (default)" save_analysis_data "wordpress_settings.tmp" " Security & performance: Disable with wp option update default_ping_status 'closed'" fi fi } # ============================================================================ # CATEGORY 2: DATABASE TUNING (8 checks) # ============================================================================ ### 2.1 - InnoDB Buffer Pool Size analyze_innodb_buffer_pool() { local buffer_pool=$(mysql -Ns -e "SELECT @@innodb_buffer_pool_size;" 2>/dev/null || echo "0") if [ "$buffer_pool" -lt 268435456 ]; then # Less than 256MB save_analysis_data "database_tuning.tmp" "CRITICAL: InnoDB buffer pool too small" save_analysis_data "database_tuning.tmp" " Current: $(( buffer_pool / 1024 / 1024 ))MB" save_analysis_data "database_tuning.tmp" " Recommend: 256MB minimum, 50-75% of available RAM" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: innodb_buffer_pool_size = 8G" fi } ### 2.2 - Max Allowed Packet analyze_max_allowed_packet() { local max_packet=$(mysql -Ns -e "SELECT @@max_allowed_packet;" 2>/dev/null || echo "0") if [ "$max_packet" -lt 16777216 ]; then # Less than 16MB save_analysis_data "database_tuning.tmp" "WARNING: max_allowed_packet is small" save_analysis_data "database_tuning.tmp" " Current: $(( max_packet / 1024 / 1024 ))MB" save_analysis_data "database_tuning.tmp" " Large queries may fail silently" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: max_allowed_packet = 256M" fi } ### 2.3 - Slow Query Log Threshold analyze_slow_query_threshold() { local long_query_time=$(mysql -Ns -e "SELECT @@long_query_time;" 2>/dev/null || echo "10") if (( $(echo "$long_query_time > 2" | bc -l) )); then save_analysis_data "database_tuning.tmp" "INFO: Slow query threshold is high (${long_query_time}s)" save_analysis_data "database_tuning.tmp" " Misses real slow queries that take 1-2 seconds" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: long_query_time = 1" fi } ### 2.4 - InnoDB File Per Table analyze_innodb_file_per_table() { local file_per_table=$(mysql -Ns -e "SELECT @@innodb_file_per_table;" 2>/dev/null || echo "0") if [ "$file_per_table" -eq 0 ]; then save_analysis_data "database_tuning.tmp" "WARNING: InnoDB file-per-table is disabled" save_analysis_data "database_tuning.tmp" " All tables in single ibdata1 file (can grow huge)" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: innodb_file_per_table = 1" fi } ### 2.5 - Query Cache (MySQL 5.7) analyze_query_cache() { local query_cache=$(mysql -Ns -e "SELECT @@version;" 2>/dev/null || echo "8.0") if [[ "$query_cache" == 5.7* ]]; then local cache_type=$(mysql -Ns -e "SELECT @@query_cache_type;" 2>/dev/null || echo "0") if [ "$cache_type" -gt 0 ]; then save_analysis_data "database_tuning.tmp" "INFO: Query cache enabled (MySQL 5.7)" save_analysis_data "database_tuning.tmp" " Can be slow, consider disabling or upgrading to MySQL 8.0" fi fi } ### 2.6 - Temporary Table Location analyze_temp_table_location() { local tmp_table_size=$(mysql -Ns -e "SELECT @@tmp_table_size;" 2>/dev/null || echo "0") if [ "$tmp_table_size" -lt 33554432 ]; then # Less than 32MB save_analysis_data "database_tuning.tmp" "INFO: Temporary table size is small" save_analysis_data "database_tuning.tmp" " Current: $(( tmp_table_size / 1024 / 1024 ))MB" save_analysis_data "database_tuning.tmp" " Large GROUP BY/DISTINCT queries go to disk" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: tmp_table_size = 512M" fi } ### 2.7 - Connection Timeout Settings analyze_connection_timeout() { local wait_timeout=$(mysql -Ns -e "SELECT @@wait_timeout;" 2>/dev/null || echo "28800") if [ "$wait_timeout" -gt 3600 ]; then save_analysis_data "database_tuning.tmp" "INFO: wait_timeout is high (${wait_timeout}s)" save_analysis_data "database_tuning.tmp" " May accumulate idle connections" save_analysis_data "database_tuning.tmp" " For pooling: Set to 600 (10 min)" fi } ### 2.8 - Innodb Flush Log at Trx Commit analyze_innodb_flush_log() { local flush_log=$(mysql -Ns -e "SELECT @@innodb_flush_log_at_trx_commit;" 2>/dev/null || echo "1") if [ "$flush_log" -eq 1 ]; then save_analysis_data "database_tuning.tmp" "INFO: InnoDB flush log = 1 (safest but slowest)" save_analysis_data "database_tuning.tmp" " Change to 2 for better performance with acceptable risk" save_analysis_data "database_tuning.tmp" " Edit /etc/my.cnf: innodb_flush_log_at_trx_commit = 2" fi } # ============================================================================ # CATEGORY 3: PHP PERFORMANCE (6 checks) # ============================================================================ ### 3.1 - OPcache Configuration analyze_opcache() { local opcache_enabled=$(php -r "echo extension_loaded('Zend OPcache') ? 1 : 0;" 2>/dev/null || echo 0) if [ "$opcache_enabled" -eq 0 ]; then save_analysis_data "php_tuning.tmp" "CRITICAL: OPcache not enabled" save_analysis_data "php_tuning.tmp" " Impact: 2-3x slower PHP execution" save_analysis_data "php_tuning.tmp" " Fix: Enable in php.ini with proper config" else local cache_size=$(php -i 2>/dev/null | grep "opcache.memory_consumption" | awk '{print $NF}' || echo "0") if [ "$cache_size" -lt 256 ]; then save_analysis_data "php_tuning.tmp" "WARNING: OPcache memory too small (${cache_size}MB)" save_analysis_data "php_tuning.tmp" " Recommend: 256MB or more" fi fi } ### 3.2 - Xdebug in Production analyze_xdebug() { local xdebug_enabled=$(php -m 2>/dev/null | grep -c "Xdebug" || echo 0) if [ "$xdebug_enabled" -gt 0 ]; then save_analysis_data "php_tuning.tmp" "CRITICAL: Xdebug enabled in production!" save_analysis_data "php_tuning.tmp" " Impact: 50-70% performance penalty" save_analysis_data "php_tuning.tmp" " Fix: Disable or uninstall immediately" fi } ### 3.3 - Realpath Cache analyze_realpath_cache() { local realpath_size=$(php -i 2>/dev/null | grep "realpath_cache_size" | awk '{print $NF}' || echo "0") if [[ "$realpath_size" == "4K" ]] || [ "$realpath_size" = "4096" ]; then save_analysis_data "php_tuning.tmp" "INFO: Realpath cache is default (4K, too small)" save_analysis_data "php_tuning.tmp" " For WordPress: Recommend 128M" save_analysis_data "php_tuning.tmp" " Edit php.ini: realpath_cache_size = 128M" fi } ### 3.4 - Timezone Configuration analyze_timezone_config() { local php_tz=$(php -i 2>/dev/null | grep "date.timezone" | head -1 | awk '{print $NF}' || echo "UTC") if [ "$php_tz" = "no value" ] || [ -z "$php_tz" ]; then save_analysis_data "php_tuning.tmp" "INFO: Timezone not configured" save_analysis_data "php_tuning.tmp" " Set to UTC or match site timezone" save_analysis_data "php_tuning.tmp" " Edit php.ini: date.timezone = UTC" fi } ### 3.5 - Display Errors in Production analyze_display_errors() { local display_errors=$(php -i 2>/dev/null | grep "display_errors" | grep -o "On\|Off" | head -1 || echo "Off") if [ "$display_errors" = "On" ]; then save_analysis_data "php_tuning.tmp" "WARNING: display_errors is On in production" save_analysis_data "php_tuning.tmp" " Security risk, performance penalty" save_analysis_data "php_tuning.tmp" " Edit php.ini: display_errors = Off" fi } ### 3.6 - Disabled Functions analyze_disabled_functions() { local disabled=$(php -i 2>/dev/null | grep "disable_functions" | grep -o "[^ ].*" | head -1 || echo "none") if [ "$disabled" != "none" ] && [ -n "$disabled" ]; then save_analysis_data "php_tuning.tmp" "INFO: Functions disabled (security): $disabled" save_analysis_data "php_tuning.tmp" " Verify these don't break any plugins" fi } # ============================================================================ # CATEGORY 4: WEB SERVER TUNING (6 checks) # ============================================================================ ### 4.1 - HTTP/2 Enabled analyze_http2() { local http2_enabled=$(apache2ctl -M 2>/dev/null | grep -c "http2_module" || echo 0) if [ "$http2_enabled" -eq 0 ]; then save_analysis_data "web_server.tmp" "WARNING: HTTP/2 not enabled" save_analysis_data "web_server.tmp" " Impact: 15-30% slower asset delivery" save_analysis_data "web_server.tmp" " Fix: a2enmod http2 && systemctl restart apache2" fi } ### 4.2 - KeepAlive Settings analyze_keepalive() { local keepalive=$(grep -A 3 "^KeepAlive" /etc/apache2/apache2.conf 2>/dev/null | head -1 || echo "unknown") if [[ "$keepalive" == *"Off"* ]]; then save_analysis_data "web_server.tmp" "INFO: KeepAlive is disabled" save_analysis_data "web_server.tmp" " Enable for better performance: KeepAlive On" fi } ### 4.3 - Sendfile Enabled analyze_sendfile() { local sendfile=$(grep -i "EnableSendfile" /etc/apache2/apache2.conf 2>/dev/null | grep -o "On\|Off" || echo "unknown") if [ "$sendfile" = "Off" ] || [ -z "$sendfile" ]; then save_analysis_data "web_server.tmp" "WARNING: Sendfile not enabled" save_analysis_data "web_server.tmp" " 10-20% faster static file delivery" save_analysis_data "web_server.tmp" " Enable: EnableSendfile on" fi } ### 4.4 - Gzip Compression Level analyze_gzip_compression() { local gzip_level=$(grep -i "DeflateCompressionLevel" /etc/apache2/mods-enabled/deflate.conf 2>/dev/null | grep -o "[0-9]" || echo "6") if [ "$gzip_level" = "9" ]; then save_analysis_data "web_server.tmp" "INFO: Gzip compression level is 9 (maximum)" save_analysis_data "web_server.tmp" " Too slow, not worth it. Recommend level 6" save_analysis_data "web_server.tmp" " Edit deflate.conf: DeflateCompressionLevel 6" fi } ### 4.5 - SSL/TLS Version analyze_ssl_version() { local ssl_version=$(grep -i "SSLProtocol" /etc/apache2/sites-enabled/*ssl.conf 2>/dev/null | grep -o "TLSv[0-9.]*" | head -1 || echo "unknown") if [[ "$ssl_version" == *"1.0"* ]] || [[ "$ssl_version" == *"1.1"* ]]; then save_analysis_data "web_server.tmp" "WARNING: Using outdated SSL/TLS: $ssl_version" save_analysis_data "web_server.tmp" " Recommend: TLS 1.2 minimum, TLS 1.3 preferred" save_analysis_data "web_server.tmp" " Set: SSLProtocol TLSv1.2 TLSv1.3" fi } ### 4.6 - Unused Apache Modules analyze_apache_modules() { local module_count=$(apache2ctl -M 2>/dev/null | wc -l || echo "0") if [ "$module_count" -gt 45 ]; then save_analysis_data "web_server.tmp" "INFO: Many Apache modules loaded ($module_count)" save_analysis_data "web_server.tmp" " Review and disable unused modules" save_analysis_data "web_server.tmp" " Command: apache2ctl -M" fi } # ============================================================================ # CATEGORY 5: CRON & BACKGROUND TASKS (4 checks) # ============================================================================ ### 5.1 - WordPress Cron Execution analyze_wordpress_cron() { local docroot="$1" if [ -f "$docroot/wp-config.php" ]; then local cron_disabled=$(grep -c "DISABLE_WP_CRON.*true" "$docroot/wp-config.php" 2>/dev/null || echo 0) if [ "$cron_disabled" -eq 0 ]; then save_analysis_data "cron_tasks.tmp" "INFO: Using wp-cron (runs every pageload)" save_analysis_data "cron_tasks.tmp" " Better: Switch to system cron" save_analysis_data "cron_tasks.tmp" " Set: define('DISABLE_WP_CRON', true);" save_analysis_data "cron_tasks.tmp" " Then add system cron: */5 * * * * curl https://example.com/wp-cron.php" fi fi } ### 5.2 - Backup Schedule analyze_backup_schedule() { local backup_time=$(grep -i "backup" /etc/cron.d/cpanel* 2>/dev/null | grep -o "[0-9]*:[0-9]*" | head -1 || echo "unknown") if [ "$backup_time" != "unknown" ]; then # Extract hour local hour=${backup_time%%:*} if [ "$hour" -ge 7 ] && [ "$hour" -le 18 ]; then save_analysis_data "cron_tasks.tmp" "WARNING: Backup scheduled during peak hours ($hour:00)" save_analysis_data "cron_tasks.tmp" " Move to 2-4 AM for off-peak" fi fi } ### 5.3 - Database Optimization Schedule analyze_db_optimization_schedule() { local has_optimize=$(grep -c "mysqlcheck\|optimize" /etc/cron.d/* 2>/dev/null || echo 0) if [ "$has_optimize" -eq 0 ]; then save_analysis_data "cron_tasks.tmp" "INFO: No database optimization scheduled" save_analysis_data "cron_tasks.tmp" " Recommend weekly: mysqlcheck -Aou database_name" save_analysis_data "cron_tasks.tmp" " Add to crontab: 0 3 * * 0 mysqlcheck -Aou -u root -p{pass}" fi } ### 5.4 - Slow Cron Jobs analyze_slow_cron_jobs() { # This requires WordPress and wp-cli to be available if command -v wp &> /dev/null; then local cron_jobs=$(wp cron schedule list 2>/dev/null | wc -l || echo "0") if [ "$cron_jobs" -gt 10 ]; then save_analysis_data "cron_tasks.tmp" "INFO: Many scheduled cron jobs ($cron_jobs)" save_analysis_data "cron_tasks.tmp" " Review with: wp cron schedule list" save_analysis_data "cron_tasks.tmp" " Disable unnecessary ones for better performance" fi fi } # ============================================================================ # ADDITIONAL HIGH-VALUE CHECKS # ============================================================================ ### Missing Critical Indexes analyze_missing_critical_indexes() { local db_name="$1" if [ -z "$db_name" ]; then return 0 fi # Check for common missing indexes local missing_indexes="" # Check wp_postmeta meta_key index local meta_key_index=$(mysql -Ns -e " SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='${db_name}' AND TABLE_NAME='wp_postmeta' AND COLUMN_NAME='meta_key'; " 2>/dev/null || echo "0") if [ "$meta_key_index" -eq 0 ]; then missing_indexes+="wp_postmeta(meta_key) " fi # Check wp_posts post_type index local post_type_index=$(mysql -Ns -e " SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='${db_name}' AND TABLE_NAME='wp_posts' AND COLUMN_NAME='post_type'; " 2>/dev/null || echo "0") if [ "$post_type_index" -eq 0 ]; then missing_indexes+="wp_posts(post_type) " fi if [ -n "$missing_indexes" ]; then save_analysis_data "database_tuning.tmp" "CRITICAL: Missing critical indexes" save_analysis_data "database_tuning.tmp" " Missing: $missing_indexes" save_analysis_data "database_tuning.tmp" " Add: ALTER TABLE table_name ADD INDEX (column_name);" fi } ### Database to Memory Ratio analyze_database_memory_ratio() { local db_name="$1" if [ -z "$db_name" ]; then return 0 fi local db_size=$(mysql -Ns -e " SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024) FROM information_schema.tables WHERE table_schema='${db_name}'; " 2>/dev/null || echo "0") local system_memory=$(free -m | awk 'NR==2{print $2}') if [ "$db_size" -gt 0 ] && [ "$system_memory" -gt 0 ]; then if [ "$db_size" -gt "$system_memory" ]; then save_analysis_data "database_tuning.tmp" "CRITICAL: Database (${db_size}MB) larger than available RAM (${system_memory}MB)" save_analysis_data "database_tuning.tmp" " This causes heavy disk I/O" save_analysis_data "database_tuning.tmp" " Solutions: Increase RAM, optimize DB, or split database" fi fi } ################################################################################ # EXPORT ALL FUNCTIONS ################################################################################ export -f analyze_wp_debug export -f analyze_xmlrpc export -f analyze_heartbeat_api export -f analyze_autosave_frequency export -f analyze_rest_api_exposure export -f analyze_emoji_scripts export -f analyze_post_revision_distribution export -f analyze_pingbacks_trackbacks export -f analyze_innodb_buffer_pool export -f analyze_max_allowed_packet export -f analyze_slow_query_threshold export -f analyze_innodb_file_per_table export -f analyze_query_cache export -f analyze_temp_table_location export -f analyze_connection_timeout export -f analyze_innodb_flush_log export -f analyze_opcache export -f analyze_xdebug export -f analyze_realpath_cache export -f analyze_timezone_config export -f analyze_display_errors export -f analyze_disabled_functions export -f analyze_http2 export -f analyze_keepalive export -f analyze_sendfile export -f analyze_gzip_compression export -f analyze_ssl_version export -f analyze_apache_modules export -f analyze_wordpress_cron ################################################################################ # PHASE 4: ADVANCED DATABASE & ISSUE PATTERN DETECTION (Tier 1 Quick Wins) ################################################################################ # ============================================================================ # PHASE 4 DATABASE CHECKS (6 quick wins) # ============================================================================ ### P4.1 - Table Engine Mismatch analyze_table_engine_mismatch() { # Check if tables use inconsistent storage engines local engines=$(mysql -e "SELECT DISTINCT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() 2>/dev/null" 2>/dev/null | grep -v ENGINE | sort -u) if [ ! -z "$engines" ] && [ "$(echo "$engines" | wc -l)" -gt 1 ]; then save_analysis_data "database_advanced.tmp" "WARNING: Mixed storage engines detected" save_analysis_data "database_advanced.tmp" " Engines: $(echo $engines | tr '\n' ', ')" save_analysis_data "database_advanced.tmp" " Recommendation: Convert all tables to InnoDB" fi } ### P4.2 - Table Statistics Age analyze_table_statistics_age() { # Check if table statistics are stale (MySQL 5.7+) local stale_count=$(mysql -e "SELECT COUNT(*) FROM mysql.innodb_table_stats WHERE STAT_MODIFIED < DATE_SUB(NOW(), INTERVAL 30 DAY)" 2>/dev/null | tail -1 || echo 0) if [ "$stale_count" -gt 0 ]; then save_analysis_data "database_advanced.tmp" "INFO: Found $stale_count tables with stale statistics" save_analysis_data "database_advanced.tmp" " Fix: Run ANALYZE TABLE on each table" save_analysis_data "database_advanced.tmp" " Or: wp db optimize (WordPress)" fi } ### P4.3 - Index Cardinality Analysis analyze_index_cardinality() { # Check for indexes with poor selectivity local poor_indexes=$(mysql -e "SELECT TABLE_NAME, INDEX_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND SEQ_IN_INDEX=1 AND CARDINALITY IS NOT NULL AND CARDINALITY / (SELECT TABLE_ROWS FROM information_schema.TABLES t WHERE t.TABLE_SCHEMA=information_schema.STATISTICS.TABLE_SCHEMA AND t.TABLE_NAME=information_schema.STATISTICS.TABLE_NAME) > 0.95 LIMIT 5" 2>/dev/null | grep -v TABLE_NAME | head -5) if [ ! -z "$poor_indexes" ]; then save_analysis_data "database_advanced.tmp" "WARNING: Found indexes with poor cardinality (high selectivity)" save_analysis_data "database_advanced.tmp" " These indexes may not be used by optimizer" save_analysis_data "database_advanced.tmp" " Review and consider dropping unused indexes" fi } ### P4.4 - Query Cache Memory Waste analyze_query_cache_memory_waste() { # Check query cache fragmentation (MySQL 5.7) local qcache_info=$(mysql -e "SHOW STATUS LIKE 'Qcache%'" 2>/dev/null) if echo "$qcache_info" | grep -q "Qcache_free_blocks"; then local free_blocks=$(echo "$qcache_info" | grep "Qcache_free_blocks" | awk '{print $2}') local total_blocks=$(echo "$qcache_info" | grep "Qcache_total_blocks" | awk '{print $2}') if [ "$total_blocks" -gt 0 ]; then local fragmentation=$((free_blocks * 100 / total_blocks)) if [ "$fragmentation" -gt 30 ]; then save_analysis_data "database_advanced.tmp" "INFO: Query cache fragmentation at ${fragmentation}%" save_analysis_data "database_advanced.tmp" " Consider: FLUSH QUERY CACHE; or redesign query strategy" fi fi fi } ### P4.5 - Replication Lag Check analyze_replication_lag() { # Check if database is replica and has lag local slave_status=$(mysql -e "SHOW SLAVE STATUS\G 2>/dev/null" | grep "Seconds_Behind_Master" | awk '{print $NF}') if [ ! -z "$slave_status" ] && [ "$slave_status" != "NULL" ] && [ "$slave_status" -gt 10 ]; then save_analysis_data "database_advanced.tmp" "WARNING: Database replication lag detected: ${slave_status} seconds" save_analysis_data "database_advanced.tmp" " Impact: Read queries on replica are stale" save_analysis_data "database_advanced.tmp" " Solution: Optimize master, increase replica resources" fi } ### P4.6 - Table Size Growth Tracking analyze_table_size_growth() { # Identify rapidly growing tables (potential logging tables) local large_tables=$(mysql -e "SELECT TABLE_NAME, ROUND(((data_length+index_length)/1024/1024),2) as size_mb FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY size_mb DESC LIMIT 5" 2>/dev/null | grep -v TABLE_NAME) if [ ! -z "$large_tables" ]; then local largest=$(echo "$large_tables" | head -1 | awk '{print $1, $2}') if echo "$largest" | awk '{exit ($2 > 1000) ? 0 : 1}'; then save_analysis_data "database_advanced.tmp" "WARNING: Large table detected: $largest MB" save_analysis_data "database_advanced.tmp" " If this is wp_postmeta or wp_options, consider archiving old data" fi fi } # ============================================================================ # PHASE 4 SYSTEM & ERROR PATTERN CHECKS (6 quick wins) # ============================================================================ ### P4.7 - Timeout Error Detection analyze_timeout_errors() { # Count timeout errors in recent logs local error_log=$(find /var/log -name "error.log" -o -name "php-fpm.log" 2>/dev/null | head -1) if [ -f "$error_log" ]; then local timeout_count=$(tail -1000 "$error_log" 2>/dev/null | grep -ci "timeout\|timed out" || echo 0) if [ "$timeout_count" -gt 10 ]; then save_analysis_data "error_patterns.tmp" "WARNING: Found $timeout_count timeout errors in recent logs" save_analysis_data "error_patterns.tmp" " Impact: Customers experiencing connection/processing failures" save_analysis_data "error_patterns.tmp" " Solutions: Increase timeouts, optimize code, add resources" fi fi } ### P4.8 - Memory Exhaustion Attempts analyze_memory_exhaustion_attempts() { # Detect PHP memory limit hits local error_log=$(find /var/log -name "error.log" -o -name "php-fpm.log" 2>/dev/null | head -1) if [ -f "$error_log" ]; then local memory_count=$(tail -1000 "$error_log" 2>/dev/null | grep -ci "allowed memory\|memory.*exhausted" || echo 0) if [ "$memory_count" -gt 0 ]; then save_analysis_data "error_patterns.tmp" "CRITICAL: PHP hitting memory limits ($memory_count times in logs)" save_analysis_data "error_patterns.tmp" " Impact: Some requests failing with fatal error" save_analysis_data "error_patterns.tmp" " Fix: Increase memory_limit in php.ini" fi fi } ### P4.9 - Disk Inode Usage analyze_disk_inode_usage() { # Check filesystem inode exhaustion (causes performance degradation) local inode_usage=$(df -i / 2>/dev/null | tail -1 | awk '{print int($5)}' || echo 0) if [ "$inode_usage" -gt 80 ]; then save_analysis_data "system_resources.tmp" "WARNING: Disk inode usage at ${inode_usage}%" save_analysis_data "system_resources.tmp" " Impact: Filesystem performance degrades, may prevent new files" save_analysis_data "system_resources.tmp" " Fix: Delete old logs, temporary files, or backups" fi } ### P4.10 - Zombie Process Detection analyze_zombie_processes() { # Count zombie/defunct processes local zombie_count=$(ps aux 2>/dev/null | grep -c " " || echo 0) if [ "$zombie_count" -gt 5 ]; then save_analysis_data "system_resources.tmp" "WARNING: Found $zombie_count zombie processes" save_analysis_data "system_resources.tmp" " Impact: Wastes process table entries, resource leak" save_analysis_data "system_resources.tmp" " Fix: Restart PHP-FPM or MySQL to clean up" fi } ### P4.11 - Swap Usage Detection (Critical) analyze_swap_usage_phase4() { # Check if system is using swap (massive performance killer) local swap_used=$(free 2>/dev/null | grep Swap | awk '{print $3}' || echo 0) if [ "$swap_used" -gt 0 ]; then save_analysis_data "system_resources.tmp" "CRITICAL: System using swap ($swap_used KB)" save_analysis_data "system_resources.tmp" " Impact: 50-100x SLOWER than RAM access" save_analysis_data "system_resources.tmp" " Emergency: Upgrade RAM or reduce memory usage immediately" fi } ### P4.12 - Load Average Trending analyze_load_average_trend() { # Detect increasing load trend (early warning) local load_1=$(uptime 2>/dev/null | grep -oP 'load average: \K[^,]+' | head -1) local load_5=$(uptime 2>/dev/null | grep -oP 'load average: \K[^,]+' | tail -2 | head -1) if [ ! -z "$load_1" ] && [ ! -z "$load_5" ]; then local ratio=$(echo "scale=2; $load_1 / $load_5" | bc 2>/dev/null || echo 1) if (( $(echo "$ratio > 1.2" | bc -l) )); then save_analysis_data "system_resources.tmp" "INFO: Load average trending upward (1min: $load_1, 5min: $load_5)" save_analysis_data "system_resources.tmp" " Early warning: Monitor for increasing problems" fi fi } ################################################################################ # EXPORT ALL PHASE 4 FUNCTIONS ################################################################################ export -f analyze_backup_schedule export -f analyze_db_optimization_schedule export -f analyze_slow_cron_jobs export -f analyze_missing_critical_indexes export -f analyze_database_memory_ratio export -f analyze_table_engine_mismatch export -f analyze_table_statistics_age export -f analyze_index_cardinality export -f analyze_query_cache_memory_waste export -f analyze_replication_lag export -f analyze_table_size_growth export -f analyze_timeout_errors export -f analyze_memory_exhaustion_attempts export -f analyze_disk_inode_usage export -f analyze_zombie_processes export -f analyze_swap_usage_phase4 export -f analyze_load_average_trend