PHP Cache Dynamic Pages To Speed Up Load Times

If your website receives a good amount of traffic everyday and your webpages are loading slow, you might want to consider implementing some sort of caching mechanism on your website to speed-up page loading time. Because as we all know that each client-server request consists of many queries, loops, calculations, database queries etc. these all add-up to processing time, which eventually increases page loading time. The most simplest way to avoid all these is to create cache files and store them in a separate directory, which can later be served as fast loading static pages instead of regular dynamic pages.

PHP Caching

There are several other PHP cache engines such as APC, Xcache or OPcache to boost your application performance, but they all work quite differently, to understand them you can find many tutorials dedicated to them on the web. Here I’m going to show you the most simplest way of caching PHP pages, and that is using PHP Output Buffer and Filesystem Functions, combining these two methods we can have magnificent caching system.

PHP Output buffer :— It interestingly improves performance and decreases the amount of time it takes to download, because the output is not being sent to browser in pieces but the whole HTML page as one variable. The method is insanely simple take a look at the code below :

1
2
3
4
5
6
7
<?php
ob_start(); // start the output buffer

/* the content */
ob_get_contents();  gets the contents of the output buffer
ob_end_flush(); // Send the output and turn off output buffering
?>

When you call ob_start() on the top of the code, it turns output buffering on, which means anything after this will be stored in the buffer, instead of outputting on the browser. The content in the buffer can be retrieved using ob_get_contents(). You should call ob_end_flush() at the end of the code to send the output to the browser and turn buffering off.

PHP Filesystem :— You may be familiar with PHP file system, it is a part of the PHP core, which allow us to read and write the file system. Have a look at the following code.

1
2
3
$fp = fopen('/path/to/file.txt', 'w');  //open file for writing
fwrite($fp, 'I want to write this'); //write
fclose($fp); //Close file pointer

As you can see the first line of the code fopen() opens the file for writing, the mode ‘w’ places the file pointer at the beginning of the file and if file does not exist, it attempts to create one. Second line fwrite() writes the string to the opened file, and finally fclose() closes the successfully opened file at the beginning of the code.

Implementing PHP caching

Now you should be pretty clear about PHP output buffer and filesystem, we can use these both methods to create our PHP caching system. Please have a look at the picture below, the Flowchart gives us the basic idea about our cache system.
PHP cache system in Action
The cycle starts when a user request the content, we just check whether the cache copy exist for the currently requested page, if it doesn’t exist we generate a new page, create cache copy and then output the result. If the cache already exist, we just have to fetch the file and send it to the user browser.

Take a look at the Full PHP cache code below, you can just copy and paste it in your PHP projects, it should work flawlessly as depicted in above Flowchart. You can play with the settings in the code, modify the cache expire time, cache file extension, ignored pages etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
//settings
$cache_ext  = '.html'; //file extension
$cache_time     = 3600;  //Cache file expires afere these seconds (1 hour = 3600 sec)
$cache_folder   = 'cache/'; //folder to store Cache files
$ignore_pages   = array('', '');

$dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)
$cache_file     = $cache_folder.md5($dynamic_url).$cache_ext; // construct a cache file
$ignore = (in_array($dynamic_url,$ignore_pages))?true:false; //check if url is in ignore list

if (!$ignore && file_exists($cache_file) && time() - $cache_time < filemtime($cache_file)) { //check Cache exist and it's not expired.
    ob_start('ob_gzhandler'); //Turn on output buffering, "ob_gzhandler" for the compressed page with gzip.
    readfile($cache_file); //read Cache file
    echo '<!-- cached page - '.date('l jS \of F Y h:i:s A', filemtime($cache_file)).', Page : '.$dynamic_url.' -->';
    ob_end_flush(); //Flush and turn off output buffering
    exit(); //no need to proceed further, exit the flow.
}
//Turn on output buffering with gzip compression.
ob_start('ob_gzhandler');
######## Your Website Content Starts Below #########
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Page to Cache</title>
    </head>
        <body>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut tellus libero.
        </body>
</html>
<?php
######## Your Website Content Ends here #########

if (!is_dir($cache_folder)) { //create a new folder if we need to
    mkdir($cache_folder);
}
if(!$ignore){
    $fp = fopen($cache_file, 'w');  //open file for writing
    fwrite($fp, ob_get_contents()); //write contents of the output buffer in Cache file
    fclose($fp); //Close file pointer
}
ob_end_flush(); //Flush and turn off output buffering

?>

You must place your PHP content between the enclosed comment lines, In fact I’d suggest putting them in separate header and footer file, so that it can generate and serve cache files for all the different dynamic pages. If you read the comment lines in the code carefully, you should find it pretty much self explanatory.

  1. Get the currently requested URL location.
  2. Construct a location path for the cache file, convert URL to MD5 hash for the fixed cache file name.
  3. Check whether URL is in ignore list.
  4. Check for existing unexpired cache file, if exist, just open and output the content with gzip compression.
  5. Or else, we create a new cache file and output the HTML result with gzip compression.

Conclusion

I hope this code will help you create your own cache system, but you must avoid caching in certain types of pages such as members area (after user logs in), search pages or a constantly updating homepage. You must also combine and compress JavaScripts, CSS and HTML to boots performance even more, and test your webpages using Google’s pageSpeed.

  1. Thank Very Much it works.

     Reply
  2. thanks. thats is work. :)

     Reply
  3. I have some experience especially about PHP Cache, thanks and nice article

     Reply
  4. Xede jıde razibe :) (Kurdish). It means that, thank you :)

     Reply
  5. thanks. thats is work. and now i can understand it.

     Reply
  6. I wanna ask something about this…
    you should find it pretty much self explanatory.

    Get the currently requested URL location.
    Construct a location path for the cache file, convert URL to MD5 hash for the fixed cache file name.
    Check whether URL is in ignore list.
    Check for existing unexpired cache file, if exist, just open and output the content with gzip compression.
    Or else, we create a new cache file and output the HTML result with gzip compression.

    how to know that url is in ignore list?

     Reply
  7. Hi,
    Once, thank you!
    I have a question. I have a ecommerce website (prestashop) I want to use this manuel dynamic cache method. But some pages make problem. For example: register, cart, shopping etc. I shouldn’t use this cache at that page. (cart,register etc.) How Can I exclude important pages ?

    It is like?
    $ignore_pages = array(‘http://mydomain.com/cart’,’http://mydomain.com/register’);

    I hope, you will give me detaily information.
    Thank you!

     Reply
  8. Really helpfull… Thanks :)

     Reply
  9. I prefer using wp plugin for wp users, it’s really simple without coding. But, this article really helping me to understand how caching web pages using PHP work. Thanks saran

     Reply
  10. An outclass work, Its helpful to understanding filesystem, output buffering too :). You have amazing writing instinct.

     Reply
  11. verry nice article, i really like it .

     Reply
  12. I just Find your website, thanks for you sharing. i will use these thoughts in my projects development

     Reply
  13. I will try it, still newbe in PHP..

     Reply
  14. Please note that this solution is great BUT has a major issue: IO! This can be a bottleneck when having a heavy trafic. A possible great solution is storing that in tmpfs (not allowed by most webhosters, so better check).

     Reply
  15. Very nice article. I’ve written my own simple cache library, Have a look at the project on github: https://github.com/f2face/FCache

     Reply
  16. Nice Article….you must write next article about secure your cache file.

     Reply
  17. Thanks for a great tutorial, it’s really amazing . I have applied this to my Social site which i am developing , the cache feature is working perfect but a little confusion arise here, Suppose we have a user A when he logged in to the site the cache is created , if some minutes after another user B got logged in then all the data that belong’s to A are shown for B instead of B own data. What i do ??? Any suggestion would be appreciated

     Reply
    • You can use two different get parameters for each user, so that the hash would be different. I believe that should work.

  18. How can I cache contents got via cURL/file_get_contents ?

     Reply
  19. It’s my first time to visit this page, but really, I like it. Very much good information that I need. Thank you for the Author. Hope you get blessing

     Reply
  20. Mani Kumar Reddy K

    ERR_CONTENT_DECODING_FAILED
    This is the error i’m getting after including your code. There are solutions on internet but none of them works for me

     Reply
    • I noticed this happened to me if I had content generated BEFORE the cache script started. Basically, just make sure that the first part of the cache script is either first on your page, or that NO content is generated before the script begins.

    • Mani Kumar Reddy K

      Yes, I figured it out! Thanks anyway! :)
      This was really helpful article!

    • I had the same issue Mani
      See my reply below to Faith. I had to change the file writting and reading and use gzcompress() now. This worked for me (I got decoding error because of the ob_gzhandler.) (Scroll down)

  21. how can i delete cache manual without ftp ?(in browser. eg: site.com/index.php?cache=delete)

     Reply
    • Manual, so you mean by hand?

      My website delivers 6-9 versions of every page (menues are in different languages and the prices are shown in different currencies), so I had to make a table, storing the page ID and the name of the cached files. If I update a particular page, I have a script that reads out that table using the pageID and deletes all stored cache files then (so users wont see old versions).

  22. Why did you turn on output buffering twice?.

     Reply
  23. Hi,

    I’m getting “Content Encoding Error” when I call the cached URL. Any help?

     Reply
    • Fathi, I had the same issue (content encoding error)
      It has to do with the gzip compression and your server configuration. I could not solve that problem on my server (although I had installed the packages), so I simply changed the script a little bit: I use gzipuncompress() now, that works for me.

      writting the file:
      $fp = fopen($cache_file, ‘w’); //open file for writing
      fwrite ( $fp, gzcompress ( ob_get_contents(), 9 ) );
      fclose($fp); //Close file pointer

      reading the cached file:
      $handle = fopen($cache_file, “r”);
      $contents = fread($handle, filesize($cache_file));
      fclose($handle);
      $str = gzuncompress($contents);

  24. Good job!!! but I have a question.

    How can we prevent the cache issue for the session that is logged out and logged in customers ??

     Reply
    • You do not want to cache pages for logged in users.

    • if ($_SESSION[‘active_session’] 1 ) //whatever values you have set…
      { read the cache file
      }
      else
      {
      //create page as usually
      }

  25. Which tools do you guys use to check page speed? I found http://www.giftofspeed.com and http://tools.pingdom.com/fpt/ so far. Are there any other better tools out there? Thanks

     Reply
  26. Hi Saran,
    Thanks for the tips. I’m wondering, compare to mod_rewrite caching, which one do you think more efficient?

     Reply
    • This one gives you more control over time and the point when you want to update pages.

      Example: my prices change automatically on a price calculation tool. Whenever a prices changed I have to delete the cache and create a new cached page version. Otherwise (no change) I keep the cached file for months and never need to re-create it.

  27. caching web pages is very important. nowdays, google put loading speed as major serp ranking factor. but i don’t know if caching is good idea for website with quick dynamic update like e-commerce site, prestashop or else. even on sites like this, browser caching is not adviced.

     Reply
    • (Website speed) It is not a major ranking factor. It is one of 200 factors.
      It is a factor if your site is loading very very slow (like > 10 seconds).

    • Agree, as long as the site isn’t too slow, it’s just a factor. Big minus factor if the site’s too slow. Even i’ve seen slow site with loading up to 5 seconds get a good serp. I think caching can be great paired with CDN. Even highly dynamic page can be CDN’ed, of course it will cost more because it will need quicker update.

  28. I will add this cache method to my site.

     Reply
  29. it works great. how can i handle a user area and this php caching method?

     Reply
  30. Great solution. it’s work like a charm, Thank for share it.

     Reply
  31. how can i see the script above work?
    i have put the script in my website, but i cant see the different with my website before i put the script

     Reply
    • If caching system is working, you should see cache generated date on the bottom of your page. Right click on your webpage and view source.

  32. Great solution and just what I was looking for. You also took the time to explain the logic which helps seeing how it all works. Thanks

     Reply
  33. Hm, I can not get this to work properly.
    It creates the cached files in the folder cache (I can download them and see the html output)

    But when I try to browse to the page, the browser simply writes that the page is unavailable (while it writes the output file…)
    Any idea? It seems it can’t read the file again.

     Reply
  34. An outclass work, Its helpful to understanding filesystem, output buffering too :). You have amazing writing instinct.

     Reply
  35. Well Done and thanks dude.Its very helpful ,i will use these thoughts in my projects development. Good Luck :)

     Reply
  36. I’m trying to find a way to unlink() a cached file, such as this:

    if ( $_GET[‘cache’] == ‘clear’ ) { unlink($cache_file); }

    I put that in the header, then added ?cache=clear but it didn’t unlink the cached file so it could be rebuilt.

    Any ideas how to accomplish this?

     Reply
  37. I’m trying to find a way to unlink() a cached file, such as this:

    if ( $_GET[‘cache’] == ‘clear’ ) { unlink($cache_file); }

    I put that in the header, then added ?cache=clear but it didn’t unlink the cached file so it could be rebuilt.

    Any ideas how to accomplish this?

     Reply
  38. Dude, you’re the best. Awesome Script!

     Reply
  39. Simple and powerfull. I´ll start using this solution in my projects. Thanks Saran!

     Reply
  40. This worked beautifully! It was easy to implement and worked straight out of the box.

    Thank you!

     Reply
  41. can we save the cache file in a specific folder on pc or its by default save in browser cache memory..

     Reply
  42. Hi, I’d like to ask the $cache_folder = ‘cache/’; //folder to store Cache files . Is it in public_html directory or in each directory where the PHP code exist?
    Thanks

     Reply
  43. Thanks for the great job.

     Reply
  44. Hey, would you tell me an example for $ignore_pages = array(”,”);? Thanks! I tried it with ‘/test/index.php’. Do you have a solution for auto refreshing the cache?

     Reply
  45. I want to ask, when I try to use this method and load a page, it show an Content Encoding Error message, what is this means?

    Thank you.

     Reply
  46. Thank you it works. But how to display cached file when user request for a particular page ?

     Reply
Message Type : Question Comment ?
  • Question : Can include code, jsFiddle, codePen etc using Markdown Syntax.
  • Comment : Short comments and questions.