views:

144

answers:

5

I have a pretty complicated index.php now, and I would like to only run it once every hour. What is the best way to achieve this? Some ideas I've had

  • Put it in APC with apc_store($page, 60*60*) - I feel this isn't what APC is for and will probably be doing something bad to the other parts of my site
  • Save the output to a filesystem somewhere - Then apache needs write access somewhere which might be a pain
  • Somehow setup apache to do the caching for me - Is this possible?
A: 

You should really take a look at Memcached (excellent php support.)

Another good option is to setup a Squid Cache Server.

cjimti
both need an extra dependancy. For this use-case, I don't know if that is warranted...
Paul Tarjan
+1  A: 

Delivering static pages is always the most optimized way. So use for example Cron, or any other schedule service of your choice, to generate a static version of your index once every hour and have it write it to a file, example index.html. You could even have it generate it as .php if you still need some dynamic parts on the index.

I would say this is the absolute best way. Of course it's some minor pain to handle the chmod setting for the file, but it's not that big of a problem.

jamietelin
A: 

Save the page into a static file and use .htaccess rules to serve up the static page.

I'm not sure on the exact details, but I think codeignitor and boost for drupal do this.

Keyo
+3  A: 
  1. When a visitor hits your page, generate the content, send it to the user and save a static file somewhere on disk.
  2. When the next visitor comes, first look for the saved file, and if it exists, serve that rather than execute all the code in your index.php file. A basic example would be

    if (file_exists($cacheFileName))
    {
        require $cacheFileName;
        exit;
    }
    
    
    // here goes the rest of your index.php code
    //..
    
    
    // assuming your output is buffered and is contained in $output:
    echo $output;
    
    
    $cacheFileName = '/path/to/your/file.inc';
    file_put_contents($cacheFileName, $output);
    
  3. Set up a cron job that will delete your saved cache file from disk every hour or as often as you need to. Alternatively, in your index.php, on every page hit check how long ago the cached file was created and generate a new cache file if it's been around longer than you'd want it to. A cron job is easier to set up though.

To answer the deep philosophical question though, saving generated output to disk in separate files is probably the best way if you don't want to rely on third party caching solutions. APC is good for caching the code that will regenerate pages when needed, and memcached is definitely overkill if we're talking about a small(ish) application.

Rowlf
Thank you. Why is on-disk storage better than APC?
Paul Tarjan
I wouldn't say one is better than the other, I'd use them for different purposes.APC is good when you have a complex application and you need to:1) speed up PHP;2) cache some user values that are expensive to generate. Such as, I don't know, a list of all available files on the system for the __autoload() function or any other variable that takes up significant resources to construct and is not user-specific, so you can cache it safely. I wouldn't chuck generated page output in APC, it's not what it's for.
Rowlf
Thank you. What is the exact drawback of putting this in APC? I don't have to fiddle with file permissions and there won't be anything cluttering up my disk (only in memory storage).
Paul Tarjan
I just don't see the point of putting HTML code in APC. APC is an opcode cache for PHP, it's not going to serve your pre-generated HTML faster than including a file from disk - there's nothing for it to speed up because there is (I assume) no PHP in the generated output. In your question, you say "I feel this isn't what APC is for". That's how I feel too :).
Rowlf
I went with a slight variation on this. I gave you an upvote and accepted my answer. Hopefully that is a good compromise :)
Paul Tarjan
A: 

I went with a slight variation on Rowlf's and jamietelin's answer.

Create 3 files:

index.html

<meta http-equiv="refresh" content="0;url=/index_update.php" />

index.php

<?php // do all your normal stuff ?>

index_update.php

<?php

$file = "index.html";
$time = 60 * 10 - (time() - filemtime($file));

# this is on the first install 
if (filemtime($file) != filectime($file))
    $time = 0;

if ($time > 0) {
    die("Data was already updated in the 10 minutes. Please wait another " . ($time) . " seconds.");
}

ob_start();
require "index.php";
$data = ob_get_contents();

$fp = fopen($file, "w");
fwrite($fp, $data);
fclose($fp);

header("Location: /");

And then a cronjob:

*/15 * * * * curl http://example.com/index_update.php

So, if someone stumbles on the page after a production push, they will just transparently create a new index.html for you, otherwise, your cronjob will make it every 15 minutes.

Just make sure index.html is writable by your apache server. If that sounds scary, then just make your cronjob run php index_update.php as another user with write priviledges to index.html. You won't have access to all the apache environment though.

Hope this helps, comments are welcome.

Paul Tarjan