<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Compression Archives &#8211; hoech.net</title>
	<atom:link href="https://hoech.net/tag/compression/feed/" rel="self" type="application/rss+xml" />
	<link>https://hoech.net/tag/compression/</link>
	<description>Webdesign und -entwicklung, professionelle Bildbearbeitung, Reinzeichnung, DTP und Prepress in Stuttgart</description>
	<lastBuildDate>Wed, 27 Nov 2013 06:58:49 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>
	<item>
		<title>GZIP compression of static assets via mod_rewrite and PHP</title>
		<link>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/</link>
					<comments>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/#comments</comments>
		
		<dc:creator><![CDATA[Florian Höch]]></dc:creator>
		<pubDate>Sun, 03 Jun 2012 17:05:16 +0000</pubDate>
				<category><![CDATA[Web development]]></category>
		<category><![CDATA[.htaccess]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Compression]]></category>
		<category><![CDATA[GZIP]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">http://hoech.net/?p=489</guid>

					<description><![CDATA[<p>Zur deutschen Version dieses Artikels To conserve bandwidth and speed up page loading, it pays off to also compress static files like stylesheets and scripts in addition to the page itself with GZIP and set meaningful cache retention times. With [&#8230;] <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/" class="more-link"><span class="meta-nav">Weiterlesen &#8594;</span></a></p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/">GZIP compression of static assets via mod_rewrite and PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div class="cta" >This PHP script has changed since its initial release. You can find the <a href="https://github.com/fhoech/gz.php">latest version of the GZIP compression script on github</a>.</div><div class="clear"></div>
<p><a href="/2012/06/03/gzip-kompression-fuer-statische-dateien-mit-mod_rewrite-und-php/"><img decoding="async" alt="" src="/wp-content/plugins/polylang/flags/de_DE.png" /> Zur deutschen Version dieses Artikels</a></p>
<p><img decoding="async" class="alignleft size-full wp-image-377" style="margin-left: -4px;" alt="" src="http://hoech.net/wp-content/uploads/2012/05/package-x-gz.png" width="66" height="73" /> To conserve bandwidth and speed up page loading, it pays off to also compress static files like stylesheets and scripts in addition to the page itself with GZIP and set meaningful cache retention times. With Apache, this process can be set up with a custom .htaccess file as dynamic on-the-fly compression with either mod_deflate, or alernatively via PHP. In my case I settled with a PHP solution which stores the compressed data on disk, so repeated requests don&#8217;t cause the files to be compressed over and over again, but only on first access (or if the file has changed). <span id="more-489"></span></p>
<p>The PHP script which takes care of the compression of requested files and stores the compressed data as .gz files on disk looks like this:</p>
<div class="list"><p class="trigger"><a href="#">PHP script</a></p><div class="toggle_container"><div class="block">
<pre class="language-php line-numbers"><code>&lt;?php

function get_content_type($file) {
    // Determine Content-Type based on file extension
    // Default to text/html
    $info = pathinfo($file);
    $content_types = array('css' =&gt; 'text/css; charset=UTF-8',
                           'html' =&gt; 'text/html; charset=UTF-8',
                           'gif' =&gt; 'image/gif',
                           'ico' =&gt; 'image/x-icon',
                           'jpg' =&gt; 'image/jpeg',
                           'jpeg' =&gt; 'image/jpeg',
                           'js' =&gt; 'application/javascript',
                           'json' =&gt; 'application/json',
                           'png' =&gt; 'image/png',
                           'txt' =&gt; 'text/plain',
                           'xml' =&gt; 'application/xml');
    if (empty($content_types[$info['extension']]))
        return 'text/html; charset=UTF-8';
    return $content_types[$info['extension']];
}

function main() {
    // Get file path by stripping query parameters from the request URI
    if (!empty($_SERVER['REQUEST_URI']))
        $path = preg_replace('/\/?(?:\?.*)?$/', '', $_SERVER['REQUEST_URI']);

    // If the path is empty, either use DEFAULT_FILENAME if defined, or exit
    if (empty($path)) {
        if (defined('DEFAULT_FILENAME')) $path = '/' . DEFAULT_FILENAME;
        else die();
    }

    $file = dirname(__FILE__) . $path;
    if (!file_exists($file)) die();

    $mtime = filemtime($file);

    // If the user agent sent a IF_MODIFIED_SINCE header, check if the file
    // has been modified. If it hasn't, send '304 Not Modified' header &amp; exit
    if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) &amp;&amp;
        $mtime &lt;= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
        exit;
    }
    
    // Determine Content-Type based on file extension
    $content_type = get_content_type($file);

    // If the user agent accepts GZIP encoding, store a compressed version of
    // the file (&lt;filename&gt;.gz)
    if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) &amp;&amp;
        in_array('gzip', preg_split('/\s*,\s*/',
                                    $_SERVER['HTTP_ACCEPT_ENCODING']))) {
        // Only write the compressed version if it does not yet exist or the
        // original file has changed
        $gzfile = $file . '.gz';
        if (!file_exists($gzfile) || filemtime($gzfile) &lt; $mtime)
            file_put_contents($gzfile, gzencode(file_get_contents($file)));
        // Send compression headers and use the .gz file instead of the
        // original filename
        header('Content-Encoding: gzip');
        $file = $file . '.gz';
    }

    // Vary max-age and expiration headers based on content type
    switch ($content_type) {
        case 'image/gif':
        case 'image/jpeg':
        case 'image/png':
            // Max-age for images: 31 days
            $maxage = 60 * 60 * 24 * 31;
            break;
        default:
            // Max-age for everything else: 7 days
            $maxage = 60 * 60 * 24 * 7;
    }

    // Send remaining headers
    header('Vary: Accept-Encoding');
    header('Cache-Control: max-age=' . $maxage);
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $maxage) . ' GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
    header('Content-Type: ' . $content_type);
    header('Content-Length: ' . filesize($file));
    
    // If the request method isn't HEAD, send the file contents
    if ($_SERVER['REQUEST_METHOD'] != 'HEAD') readfile($file);
}

main();

?&gt;</code></pre>
</div></div></div>
<p>The script is stored as &#8218;gz.php&#8216; inside of the root directory of my WordPress installation. It detects if files have changed and recompresses them if needed. In addition it sends a &#8218;304 Not Modified&#8216; header if a file hasn&#8217;t changed since it was last requested. Furthermore we need to adjust the  .htaccess file. For my own WordPress installation it looks like this:</p>
<div class="list"><p class="trigger"><a href="#">.htaccess</a></p><div class="toggle_container"><div class="block">
<pre class="language-apache line-numbers"><code># Set 'Vary' response header for .gz files
&lt;FilesMatch "\.gz$"&gt;
&lt;IfModule mod_headers.c&gt;
Header always append Vary "Accept-Encoding"
&lt;/IfModule&gt;
&lt;/FilesMatch&gt;

&lt;IfModule mod_expires.c&gt;
ExpiresActive On
ExpiresByType application/json "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType application/xml "access plus 1 week"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/html "access plus 1 week"
ExpiresByType text/plain "access plus 1 week"
&lt;/IfModule&gt;

# BEGIN WordPress
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&lt;/IfModule&gt;
# END WordPress

# BEGIN GZIP
&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;
# END GZIP</code></pre>
</div></div></div>
<p>For .gz file access, a &#8218;Vary&#8216; header is sent to enable correct caching over proxies. Following this directive are several directives for cache retention times (&#8218;Expires&#8216; and &#8218;Cache Control&#8216; header, users may change those as it suits them. In my case, CSS and JS files expire after one week and images after one month.</p>
<p>Alternatively, the mod_rewrite rule for the PHP script can be changed so only the first request calls upon the script, and subsequently the .gz files are accessed directly (which has the drawback that you need to remember to delete any .gz files manually if you make changes, but doesn&#8217;t need to call PHP for each file access):</p>
<pre class="language-apache line-numbers"><code>&lt;IfModule mod_rewrite.c&gt;
# If the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and if gzip-encoded version of the requested file exists (&lt;file&gt;.gz)...
RewriteCond %{REQUEST_FILENAME}.gz -f
# ...then serve the gzip-encoded file. Done.
RewriteRule ^(.+)$ $1.gz [L]
# Or if the user agent accepts gzip encoding...
RewriteCond %{HTTP:Accept-Encoding} gzip
# ...and the requested file exists...
RewriteCond %{REQUEST_FILENAME} -f
# ...then use a PHP script serve a compressed version. Done.
RewriteRule \.(css|html|ico|js|json|txt|xml)$ /gz.php [L]
&lt;/IfModule&gt;</code></pre>
<p class="small">Credits: .gz-Icon based on generic package icon from <a href="http://art.gnome.org/themes/icon/1352" target="_blank">GNOME 2.18 Icon Theme</a>, released under <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0">GNU GPL 2.0 Lizenz</a></p>
<p class="small"><a class="alignleft" href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/" target="_blank" rel="license"><img decoding="async" style="border-width: 0;" alt="Creative Commons Lizenzvertrag" src="http://i.creativecommons.org/l/by-nc-sa/3.0/de/88x31.png" /></a> This article was published under <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="_blank" rel="license">Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)</a>.</p>
<p>Der Beitrag <a href="https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/">GZIP compression of static assets via mod_rewrite and PHP</a> erschien zuerst bei <a href="https://hoech.net">hoech.net</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://hoech.net/2012/06/03/gzip-compression-of-static-assets-via-mod_rewrite-and-php/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss><!-- hyper cache: hoech.net/tag/compression/feed/index.dat 26-06-24 06:58:11 -->