How to create a simple and efficient PHP cache

When working on php websites made from scratch and without a framework, speed can often be an issue. Caching is extremely useful in order to speed up PHP webpages. In this article, I'll show you a super easy and efficient way to dynamically cache php pages that need to be faster.

Step one: Create the top-cache.php file

We need to create two files. Here’s the first one: Create a new file named top-cache.php and paste the code below in it.

$break = Explode('/', $url);
$file = $break[count($break) - 1];
$cachefile = 'cached-'.substr_replace($file ,"",-4).'.html';
$cachetime = 18000;

// Serve from the cache if it is younger than $cachetime
if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
    echo "<!-- Cached copy, generated ".date('H:i', filemtime($cachefile))." -->\n";
ob_start(); // Start the output buffer

So, what this code does? The first 5 lines create the cached file name according to the current php file. So, if you’re using a file named list.php, the cached file will be named cached-list.html.

Line 6 creates a $cachetime variable which determines the life of the cache.

Lines 9 to 13 are a conditional statement which look for a file named $cachefile. If the file is found, a comment is inserted (line 10) and the $cachefile file is included. Then, the exit statement stops the execution of the script and the file is sent to the client brother. Which means that if a static file is found, no php code is interpreted by the server.

Line 14 creates a buffer, if the $cachefile file isn’t found. That’s all for the top-cache.php file.

Step two: Create the bottom-cache.php file

Now, create a second php file, named bottom-cache.php and paste the code below in it.

// Cache the contents to a file
$cached = fopen($cachefile, 'w');
fwrite($cached, ob_get_contents());
ob_end_flush(); // Send the output to the browser

If a file named $cachefile isn’t found on your server, this code is executed and create the file, so next time the page will be called, the $cachefile static file will be served to the client browser instead of executing the whole PHP file.

Step three: Include cache files on your page

Now that you have created the two necessary files, you simply have to include them on the php page you wish to cache. As you probably guessed, the top-cache.php file must be included in the beginning of your php page and the bottom-cache.php at the end, as shown below:



// Your regular PHP code goes here


Now if you test the cache on a slow page, you’ll be amazed by how faster the page is. This easy cache is my favorite solution when working on “from scratch” PHP websites.

  • Nice straight forward post. Thanks.

  • Why use “fopen”, “fwrite” and “fclose” when you can simply file_put_contents(ob_get_contents())?

    • For performance gain. file_get_contents and file_put_contents are slower.

  • What about $_POST, $_GET, $_COOKIE, $_REQUEST values ?
    list.php => cached.list.html
    list?php?id=123 => cached-list.html
    Same file ? o_O

    Also :
    $url = $_SERVER[“SCRIPT_NAME”];
    $break = Explode(‘/’, $url);
    $file = $break[count($break) – 1];
    is equal to this simple line :
    $file = basename( $_SERVER[“SCRIPT_NAME”], ‘.php’ ); // is enought

    • Sky

      Julio, i think the point of the directory parsing is that he must most probably use like a htaccess and not have many, or any vars with _GET. (i myself hardly never use _GET vars anymore…)

      You could just encode the REQUEST_URI to make a uniq identifier with _GET and all.

      For the _POST, its not a real problem because i dont think you want to cache that.

      Very nice script.
      Thx for sharing !

  • I believe apache does what you are doing using Disk Cache

    However If its data that is holding you down, I would use memcache. There is a php memcache client that is pretty usefull. I suppose both will require you to have access to install/configure memcache or apache. So your solution would be helpfull then.

  • David Runion

    I wrote a similar php cache about a year ago, found it to be so simple to build that I hesitated to put it into production use, thinking I must have missed something. We don’t get much traffic (~10k unique visitors / month) so I’ve kept this in my back pocket. I ended up implementing a fallback MySQL server which has been the weakest link when we get a flood of requests.

    My script handles $_GET variables and doesn’t return a cached page if $_POST is non-empty.

    I found it easy and satisfying to build, and looking over it today, surprisingly readable!

    If anyone looks at that gist, it’ll be the first time anyone has looked at my PHP code ever, so let me know what you think.

    One big difference with my setup is I’m using the PHP setting auto_prepend which allows you to have a file automatically include()d on every PHP page, and then I use PHP shutdown functions (which are passed the full text/html that is about to be output to the browser) to save the cache file. You can specify the shutdown function in the auto_prepend code and they’ll be run at the very end. You can also set the PHP variable auto_append which works as you would expect.

  • Thanks for your sharing. I have a site using PHP from scratch but don’t have cache system. I think this tutorial is really what I need

  • Please, please use Varnish.

  • really useful and simple!!!

  • Bottom cache file??? why? Yo can define a callback before push the buffer:

    ob_start(function ($buffer) {
    //save $buffer
    return $buffer;

    I think we do all that effort, having already made tools is trying to reinvent the wheel.

    I works in a cache package for PHP with good results in hi-performs stages:

    There are a class called “PageCache”, with a very simple implementation, and supports disk cache, memcache and redis

    PD: Sorry my english!

  • Please use readfile instead of include, if i write a comment like this Your cache may redirect to mine 😉

  • Hey Jean-Baptiste Jung,

    Another awesome post. Had no idea that cache was so easy to make. Good stuff, combined with all of the comments. This results in a solid post. Thanks.

  • My friend and I once made a speed test – MySQL vs raw files. I assume that if you need to get specific results from a MySQL DB, you’d be better off getting it from the MySQL DB if you needed to search for it as it is indexed rather than caching it. Right?

    Else, great post. Thank you. I learned a lot from it.

  • This cache is a good simple solution, but isn’t as fast as it could be, as the PHP file is still being parsed. The best caching mechanism would not go through PHP at all if a cached version is available. This is what the WP Super Cache and W3 Total Cache plugins for WordPress both do.

    This could be done using a rewrite rule, or via a caching proxy like Varnish or HAProxy.

  • I made a version now where the bottom part is called via the callback function of ob_start. So there is just one file to be included. Not too difficult, nevertheless it was quite tricky, because of a php bug, where den cad (current directory) is changed within the callback function.

    One solution is to define a constant outside of the callback function with the directory in it and use that constant in the callback function

    define(“CACHEFILE”, str_replace(“\\”, “/”, realpath(dirname(__FILE__))).”/cache/”.$filename);


    p.s.: “bottom part”

    ob_start(“cache_it”); // Start the output buffer

    function cache_it($buffer) {
    $cached = fopen(CACHEFILE, ‘w’);
    fwrite($cached, $buffer);
    return $buffer;

  • Probably this function is better:
    $dir_cache = dirname(__FILE__) . ‘/wp-content/cache/’;
    if( !is_dir($dir_cache) ) mkdir( $dir_cache, 0777, true );
    $file = $_SERVER[‘REQUEST_URI’];
    if(strlen($_SERVER[‘REQUEST_URI’]) > 100) {
    $file = substr($_SERVER[‘REQUEST_URI’], 0, 100);
    $file = str_replace(array(‘/’, ‘.html’, ‘.htm’), array(‘-‘, ”, ”), $file);
    $file = trim($file, ‘-.’);
    $file = preg_replace(“#[\”\’]#”, ”, $file);
    $file = preg_replace(“#[^a-z0-9-.]#i”, ”, $file);
    if(empty($file)) $file = ‘index’;
    $cachefile = $dir_cache . ‘cached-‘ . $file . ‘.html’;
    $cachetime = 18000;

    // Serve from the cache if it is younger than $cachetime
    if (file_exists($cachefile) && time() – $cachetime < filemtime($cachefile)) {
    echo "\n”;
    ob_start(); // Start the output buffer

    Why? Bacouse cache is saving to the cache directory inside wp-content dir. You caching whole site but not only one file (index.php)

  • Donovan

    So what is the actual speed gain with this type of caching system?

  • Arnold Jose

    I just want to thanks, this is a usefull piece of code, it works for me, just a note I tried

    $file = basename( $_SERVER[“SCRIPT_NAME”], ‘.php’ );

    as Julio Potier said but it didn’t work in mediatemple, it works with the original code.

    thanks for sharing.

  • okubax

    Thanks for this. It works and create a “cached-index.html” file on the first run, but on refrehing the page, it gives me an error “Parse error: syntax error, unexpected ‘version’ (T_STRING) in /home/****/public_html/cached-index.html on line 1

    Any help?

    • okubax

      Its was an error on one of the template files, now working perfectly. Many thanks

  • Excellent trick.

    Just one thing. How to exclude a particular piece of code from being cached?

    For e.g. I have a rating code which also gets cached. When people are viewing the webpage, they are not able to rate because the entire code is cached. I have add the rating code using the include statement.

    Thanks in advance

  • Mittul Chauhan

    memcache is a good one .. but i like your thoughts as well .. looking forward to use this thing in future projects ..


  • Juan Pablo Rodriguez

    This is great, do you know how to handle pages that receive get parameters?

    • Rich Aubuchon

      Try modifying as such:

      $cachefile = ‘file’;

      // create a file name based on the url
      foreach($_GET as $key=>$val) {

      // append the .html extendsion

      or you could simply take the full URL and put it into an md5 hash, and you won’t have to worry about the parameters

      $cachefile = $_SERVER[‘HTTP_HOST’].$_SERVER[‘REQUEST_URL’];
      $cachefile = md5($cachefile).”.html”;

      • @Rich Hello, how can we store these cached files on remote server and include them when needed?

  • Jeroen

    Its a good script, but when you have a login, you need to add a IP to the file because you pick the wrong file. Sorry for my bad english, i’m dutch haha.

  • shivinck

    @najmahassaan:disqus google it

  • shivinck


  • Great Explanation, thanks!

  • Sorry for stupidness, but how can I reuse the script to cache different php files? If I put

    top/bottom-cache.php includes to several files only one is created…

    • Guest

      As Rich Aubuchon mentioned use:
      $cachefile = $_SERVER[‘HTTP_HOST’].$_SERVER[‘REQUEST_URL’];
      $cachefile = md5($cachefile).”.html”;
      (only its not REQUEST_URL but REQUEST_URI)

  • Fully Help

    Checkout Great beginning php tutorials that are Very clear and helpful for beginners.

  • rahulmandaliya

    this cache is not working when page get more time to first time and cache started but if page is not loaded fully and use cloase page then cache stored partial loaded.

    is there any solution to check page fully loaded ?

    • mr android

      same to me, the cache stored not fully loaded sometimes

  • Shobhit Sharma

    Same problem,, does anyone has a solution for this?

  • Ricardo Sud

    The time is in seconds? Milliseconds?

    • Ednaldo Neimeg

      You can’t refresh the cash every 18000 milisecond (18 seconds).

    • Krzysztof C

      18000 seconds 😛

  • Not sure why mine’s not working in my site

  • this scrip works, but screws up my pagination.. Also I noticed if you include the tip-cache.php within your tags it will disable your style.css

    • Jiann Tsong

      Same with you too

  • Toby

    Is it possible to store all cahched files in a seperate folder called “cache” ?

    • Yes, I think you can change filename by adding the path like “cache/cachefile.html”.

      Best regards,

    • whatsapptube

      You can do it change top-cache.php add cache/ in the $cachefile
      $cachefile = ‘cache/cached-‘.substr_replace($file ,””,-4).’.html’;

      also make sure you create the cache folder

  • Thanks a lot. Your code is simple but very effective, reduced my server load 20 times!

  • You should put put top-cache.php before , and put bottom-cache.php after

  • superb, faced no issue,
    just curious, I have some forms in my site, will cache effect those??

  • Thank you for your php caching code. I’ll contact you again later if i found any problem while implement it

  • Ekwav

    But if the output of my page depends on a variable, thats passed in fia url, does it cache it for every variable?

  • Rimom Aguiar

    Thank you very much for the code, I’ve made a small adjust in the “top-cache.php” when there are a lot of page been generated dynamicaly from the same page, like, in this case the generated cache will be from /post.php?id=…..

    $url = $_SERVER[“REQUEST_URI”];
    $cachefile = ‘cache’.$url.’.html’;//folder=”cache”, $url=/post.php?id=…..
    $cachetime = 18000;

    // Serve from the cache if it is younger than $cachetime
    if (file_exists($cachefile) && time() – $cachetime < filemtime($cachefile)) {
    echo "n”;
    ob_start(); // Start the output buffer

  • Luis Lara

    OMG! amazing tutorial

  • Beshoy Refaat

    Thank you, this really helped alot !

  • Kiran Reddy

    I want to save and get part of html page from cache, Is it possible?