$content, 'method' => 'none', 'original_size' => $original_size, 'compressed_size' => $original_size, 'ratio' => 0 ); } } // Compress based on method switch ($method) { case 'brotli': if (function_exists('brotli_compress')) { $compressed = brotli_compress($content, $level); if ($compressed !== false) { return array( 'content' => $compressed, 'method' => 'brotli', 'original_size' => $original_size, 'compressed_size' => strlen($compressed), 'ratio' => round((($original_size - strlen($compressed)) / $original_size) * 100, 1), 'encoding' => 'br' ); } } // Fall through to gzip if brotli fails case 'gzip': if (function_exists('gzencode')) { $compressed = gzencode($content, $level); if ($compressed !== false) { return array( 'content' => $compressed, 'method' => 'gzip', 'original_size' => $original_size, 'compressed_size' => strlen($compressed), 'ratio' => round((($original_size - strlen($compressed)) / $original_size) * 100, 1), 'encoding' => 'gzip' ); } } break; default: // No compression break; } // Return uncompressed if all methods fail return array( 'content' => $content, 'method' => 'none', 'original_size' => $original_size, 'compressed_size' => $original_size, 'ratio' => 0 ); } /** * Check if content is suitable for compression */ public static function should_compress($content, $content_type = '') { // Don't compress if content is too small if (strlen($content) < 1000) { return false; } // Don't compress if already compressed $compressed_types = array('image/', 'video/', 'audio/', 'application/zip', 'application/gzip'); foreach ($compressed_types as $type) { if (strpos($content_type, $type) !== false) { return false; } } // Don't compress binary content if (!mb_check_encoding($content, 'UTF-8') && !self::is_text_content($content)) { return false; } return true; } /** * Check if content appears to be text-based */ private static function is_text_content($content) { // Simple heuristic: if most bytes are printable ASCII or common UTF-8, it's probably text $text_chars = 0; $total_chars = min(strlen($content), 1000); // Sample first 1000 bytes for ($i = 0; $i < $total_chars; $i++) { $byte = ord($content[$i]); if (($byte >= 32 && $byte <= 126) || $byte == 9 || $byte == 10 || $byte == 13) { $text_chars++; } } return ($text_chars / $total_chars) > 0.7; // 70% text characters } /** * Get compression method capabilities */ public static function get_capabilities() { return array( 'brotli' => function_exists('brotli_compress'), 'gzip' => function_exists('gzencode'), 'auto' => function_exists('brotli_compress') || function_exists('gzencode') ); } /** * Get recommended compression level for method */ public static function get_recommended_level($method) { switch ($method) { case 'brotli': return 6; // Good balance for Brotli case 'gzip': return 6; // Standard for Gzip case 'auto': return 6; // Safe default default: return 6; } } /** * Estimate compression savings */ public static function estimate_savings($content_size, $method = 'auto') { $estimates = array( 'brotli' => 0.75, // 75% compression typically 'gzip' => 0.65, // 65% compression typically 'auto' => 0.70 // Average of both ); $ratio = $estimates[$method] ?? $estimates['auto']; return round($content_size * $ratio); } }