PHP Tutorial: Dynamically Cache and Combine All CSS Files
Does your website use a lot of CSS files? If so did you know you can increase your website’s speed by caching and combining all of your CSS files into a single file?
Why Is It Useful?
Every time your browser loads a page on your website it has to make a request for all of the resources included or displayed on your page. Resources consist of things like image files, JS files, XML files and CSS files. If you find that you have more than one CSS file that you need to include on your website the requests required to load each of those files can sometimes take longer than a single request to load a single larger file. If you combine and cache your CSS files into a single file you can improve your website’s response time.
What’s a Cache?
A cache is a snapshot of a file at a moment in time. Typically you want to cache files that are static, meaning they don’t change often. If your file changes are fairly frequent then you end up generating a cache file too frequently for it to be of any use. That’s why this is a great technique to use with CSS files since they aren’t static but they don’t change that often either.
Setup
- Create two files, one called cache.css and another called cache.php.
- Place both of them in the same folder directory that you keep your style sheets in. We’ll use the CSS file to create a snapshot of all of our CSS files in our style sheet directory and we’ll use the PHP file to check generate and return the contents of our cache file.
- Change the permissions on the cache.php file to 0755. This will allow your PHP file to modify your cache.css file.
- Update the website page headers so instead of loading each of your individual .css files you’re now only loading your cache.php file
Before
<html> <head> <link href="stylesheets/filename1.css" rel="stylesheet" type="text/css" /> <link href="stylesheets/filename2.css" rel="stylesheet" type="text/css" /> <link href="stylesheets/filename3.css" rel="stylesheet" type="text/css" /> </head> <body> This is what the header would look like before updating to the single file. Notice how you're making reference links to multiple .css files. Each of those requires your browser to make a request in order to load the three separate files. </body> </html>
After
<html> <head> <link href="stylesheets/cache.php" rel="stylesheet" type="text/css" /> </head> <body> This is what the header looks like. It now references our cache.php file which will give it the cached version of our CSS files. </body> </html>
The Code
Inside of your cache.php file put the following code:
<?php /** * File: cache.php * Author: design1online.com, LLC * Purpose: updates and loads the current css cache file **/ $path = "path_to_your_public_directory/"; $dir = "name_of_your_css_folder_directory/"; $cachefilename = "cache.css"; $files_to_cache = array( "filename1.css", //add all of your css file names "filename2.css", //that are inside your_css_folder_directory "filename2.css" //that you want to cache ); //check for file changes if ($handle = opendir($path . $dir)) { while (false !== ($entry = readdir($handle))) { //if any of the $files_to_cache have changed recently we need to update the cache file //to do this we compare the last modified times on the files to see if one of our //$files_to_cache was updated more recently than our cache file if (is_file($entry) && is_readable($entry) && substr($entry, -3, 3) == "css" && date(date(filemtime($entry)) > filemtime($path . $dir . $cachefilename))) { //we've found a $file_to_cache that was updated more recently than the cache file //so open the cache file and prepare to overwrite the contents with the changes $cachefile = fopen($path . $dir . $cachefilename, "w"); //write all of the $files_to_cache to the cache file foreach ($files_to_cache as $filename) { $copyfile = fopen($path . $dir . $filename, "r"); fwrite($cachefile, fread($copyfile, filesize($filename))); fclose($copyfile); } //close the connection to the cache file - this also updates the last modified time //on the cache file so that it won't try to re-generate the cache file again until //a $files_to_cache has been changed again fclose($cachefile); //since we found one file that was changed and we've updated the cache file //we no longer need to look for other files that may have potentially been updated, so //this will tell the loop to stop running break; } } } //output the contents of the cache file //the header content type will make sure the //browser interprets the file contents as text/css header("Content-type: text/css"); //clear the buffers to prevent overflows ob_clean(); flush(); //open and return the contents of the cachefile //you'll notice your cache file contains all of your //$files_to_cache merged into one readfile($path . $dir . $cachefilename);
Last But Not Least
Update the $path, $dir and $cachefile name as needed at the top of your new cache.php file. This will tell the file where to find your css stylesheets and which ones you want to cache. Since this script looks at the last modified dates on our $files_to_cache we need to make sure and update one of the files in our $files_to_cache list in order for it to generate our initial cache.css file. To do this I would recommend making a change to one of your $files_to_cache or using touch to update the last modified time stamp on one of your $files_to_cache. Once you’ve done that you can view any page you updated to use cache.php as it’s stylesheet (see setup step 4) in any web browser to view the results of your efforts.
Looks pretty interesting as method
I’m wondering if you ever had think about doing the same for javascripts…
Additionally, I’m reading the available comments in the php file, I would suggest to write an example for the various paths
$path = “path_to_your_public_directory/”;
$dir = “name_of_your_css_folder_directory/”;
I’ll try this out
Thank you
Robert
Yes I’ve done the same for Javascript but typically I would suggest running a minifier like grunt or gulp instead.
P.S.
let’s say I have the following structure in my CSS directory
/css
/css/cssSet1
where I do have
/css/style.css
/css/mainSet1.css
/css/cssSet1/subSet1.css
from the comments it is not clear if I can use them or should I move the “subSet1.css” from /css/cssSet1 to the /css directory
Thank you for any clarification
Robert
You can use any directory/file structure you want just add it to the files array.