Cacheing script, don't connect if cache timer has not expired.

Discussion in 'Web Design and Development' started by Cabbit, Oct 20, 2009.

  1. Cabbit macrumors 68020

    Cabbit

    Joined:
    Jan 30, 2006
    Location:
    Scotland
    #1
    Right now i have a template class that builds up cache files, it is based on a tutorial that i have been modifying to better accommodate the project i am working on.

    The issue is in the index.php file, what i want it to do is only make a call to the database if ether the cache file does not exist or the cache has expired.

    Now this is kinda working just now but every now and then i get a error message from the templateParser that no tags were sent, this could only occur on the '/* do not connect to database, use existing cache file instead. */' statement, i am unsure how to rectify this though i assume it is my lack of experience in the working with cacheing pages.

    In the future i am going to look into making the cache files as XML as my lectures at Uni talk quite fondly of this but i have yet to get into how these work and that is a problem for another day.


    templateParser.php
    PHP:
    <?php
    /*
        templateParser
        KittenBunny 2.0
        Jerry Roy
    */

    class templateParser 
    {
        
    /*
            Set the output variable
        */
        
    public $output;
        
        
    /*
            function to set the template and cache file
        */
        
    public function templateParser($tags=array(),$cacheFile='default_cache.txt',$expireTime=3600$templateFile='default_template.htm')
        {
            if(!
    $this->output=$this->readCache($cacheFile,$expireTime))
            {
                (
    file_exists($templateFile))?$this->output=file_get_contents($templateFile)
                :die(
    'Error:Template file '.$templateFile.' not found');
                
    $this->parseTemplate($tags,$cacheFile);
            }
        }
        
        
    /*
            Function to sent the content to the template
        */
        
    public function parseTemplate($tags,$cacheFile)
        {
            if(
    count($tags)>0)
            {
                foreach(
    $tags as $tag=>$data)
                {
                    
    $data=(file_exists($data))?$this->parseFile($data):$data;
        
                    
    // this is the cached version
                    
    $this->output=str_replace('{'.$tag.'}',$data,$this->output);
        
                }
                
    // cached 
                
    $this->writeCache($cacheFile,$this->output);
        
            }
            else 
            {
                die(
    'Error: No tags or files were provided for replacement');
            }
        }
        
        
    /*
            Parse's the file
        */
        
    public function parseFile($file)
        {
            
    ob_start();
            include(
    $file);
            
    $content=ob_get_contents();
            
    ob_end_clean();
            return 
    $content;
        }
        
        
    /*
            Writes the cache file
        */
        
    public function writeCache($cacheFile,$content)
        {
            
    $fp=fopen($cacheFile,'w');
            
    fwrite($fp,$content);
            
    fclose($fp);
        }
        
        
    /*
            Read the cache File
        */
        
    public function readCache($cacheFile,$expireTime)
        {
            if (
    file_exists($cacheFile) && filemtime($cacheFile)>(time()-$expireTime))
            {
                return 
    file_get_contents($cacheFile);
            }
            return 
    false;
        }
        
        
    /*
            Return the populated template
        */
        
    public function display()
        {
            return 
    $this->output;
        }
    }
    ?>
    index.php
    PHP:
    try 
    {        
        
    /* Check if a cache file is ready made */
        
    if (file_exists($cacheFileIndex)) 
        {
            
    /* do not connect to database, use existing cache file instead. */
        
    }
        else
        {
            
    /* Creates a new cache file and displays the output from the cache file */
            
            /* Connect to the table */
            
    $task "dbmysql";
            
    $query_select "select `body`, `header` from `bootstrap`";
            
    $database_name "testcms";
            
            
    /* Initialise the database */
            
    $dbC = new DbControl($task"cp1250");
            
    $dbC->selectDb($database_name);
            
    $dbC->setQuery($query_select);
            
    $dbR $dbC->initiate();
            
            
    /* Prepair the data for writing the new cache file */
            
    $output=array
            (
                
    'header'=>$dbR->get("header"),
                
    'body'=>$dbR->get("body")
            );
        }
            
        
    /* Write the new data into the cache file */
        
    $output =&new templateParser($output,$cacheFileIndex,10,'../application/modules/bootstrap/views/IndexView.tpl.htm');
        
    /* Displays the output from the cache file */
        
    echo $output->display();
    }
    catch (
    Exception $e) {
        echo 
    '<p>A database connection error was found. Please try again later.</p>';
    }
     
  2. SrWebDeveloper macrumors 68000

    SrWebDeveloper

    Joined:
    Dec 7, 2007
    Location:
    Alexandria, VA, USA
    #2
    If your only issue is how to properly cache a file using file timestamp, here's what I do:

    PHP:
    // Check if cache file exists and has not expired...
    $expireTime=3600// in seconds, i.e. one hour in this case

    $cachefile=$_SERVER['DOCUMENT_ROOT']."/path/to/cachefile.ext";
    if (
    file_exists ($cachefile) && filemtime($cachefile) > (time()-$expireTime)) {
         
    // Cache exists and has not expired so output the cache file instead of database activity...
        
    $feed_data=file_get_contents($feed_cachefile);  
        
    // Output it however you want, i.e. print or send headers, whatever... 
       //  This is only a proof of concept example    
    }
    The comments explain functionality. You'd do your database call in the "do whatever here" portion of the code. Hope this is what you're looking for, it's easy enough and works. I use this for server side caching RSS feeds generated by my site which involves the database, for example.

    -jim
     
  3. Cabbit thread starter macrumors 68020

    Cabbit

    Joined:
    Jan 30, 2006
    Location:
    Scotland
    #3
    Ok so it works like this but i am just posting it to make sure its ok in your eyes, mine are not yet as experienced(something i was hoping i would get more of in uni but were using coldfusion because it is easier :( ).

    PHP:
    try 
    {        
        
    $expireTime=3600// in seconds, i.e. one hour in this case

        /* Check if a cache file is ready made */
        
    if (file_exists ($cacheFileIndex) && filemtime($cacheFileIndex) > (time()-$expireTime)) {
         
    // Cache exists and has not expired so output the cache file instead of database activity...
        
    $feed_data=file_get_contents($cacheFileIndex); 
            
    /* do not connect to database, use existing cache file instead. */
        
    }
        else
        {
            
    /* Creates a new cache file and displays the output from the cache file */
            
            /* Connect to the table */
            
    $task "dbmysql";
            
    $query_select "select `body`, `header` from `bootstrap`";
            
    $database_name "testcms";
            
            
    /* Initialise the database */
            
    $dbC = new DbControl($task"cp1250");
            
    $dbC->selectDb($database_name);
            
    $dbC->setQuery($query_select);
            
    $dbR $dbC->initiate();
            
            
    /* Prepair the data for writing the new cache file */
            
    $feed_data=array
            (
                
    'header'=>$dbR->get("header"),
                
    'body'=>$dbR->get("body")
            );
        }
            
        
    /* Write the new data into the cache file */
        
    $output =&new templateParser($feed_data,$cacheFileIndex,$expireTime,'../application/modules/bootstrap/views/IndexView.tpl.htm');
        
    /* Displays the output from the cache file */
        
    echo $output->display();
    }
    catch (
    Exception $e) {
        echo 
    '<p>A database connection error was found. Please try again later.</p>';
    }
     
  4. Cabbit thread starter macrumors 68020

    Cabbit

    Joined:
    Jan 30, 2006
    Location:
    Scotland
    #4
    Also as a boot note my plan is to reduce database access to near null. Which is why i am cacheing everything so that say on my forum all the posts are cached individually so if a user comes along or a thousand users come along there would only have been one database call instead of a thousand, the way i handed edited data is to delete the old cache file and have it rewritten by this script.
    My question here is this about the way other developers are going? or are there flaws in this design i have missed out?


    p.s. The caches will always refresh after a hour or so, and once i work out how to use XML the files will write out as XML files instead of formatted html.
     
  5. SrWebDeveloper macrumors 68000

    SrWebDeveloper

    Joined:
    Dec 7, 2007
    Location:
    Alexandria, VA, USA
    #5
    That's the right idea, only issue I can see after a quick glance is you need to use your own code to output the cached version of the file. You still have my code, i.e.:

    PHP:
    $feed_data=file_get_contents($cacheFileIndex);


    All that does is stuff a variable with the contents - no output or whatever. In the future if you want to output the XML file (such as an RSS feed upon subscription by a user) append this code to that line:

    PHP:
    header('Content-Type: text/xml');
        print 
    $feed_data;
        exit(
    0);
    -jim






     
  6. Cabbit thread starter macrumors 68020

    Cabbit

    Joined:
    Jan 30, 2006
    Location:
    Scotland
    #6
    Perhaps you could also assist with this little snippet i been working on.
    I can't get it to stop returning the page not found portion and it echos it out twice at that.

    PHP:
    /*
        The page Location.
    */
    $page explode('/'$_GET['page']);

    /*
        Load the modules based on page location.
    */
    $i 0;
    /* Opens the modules directory */
    $modulesDirectory opendir("../application/modules/");

    /* Gets the modules name based on the directory name for each module. */
    while ($moduleName readdir($modulesDirectory)) 

        if (
    $moduleName!= "." && $moduleName!= ".."
        { 
            if (
    $page[0] == $moduleName)
            {
                
    /* If the current page matches a module name, return that module. */
                
    include ("../application/modules/".$moduleName."/".$moduleName.".php");
            }
        } 
        else if (
    $page[0] == '' && $i == 0)
        {
            
    /* If the current page is the / then return the bootstrap. */
            
    include ("../application/modules/example_module/example_module.php");
            
    $i++;
        }
        else if (
    $page[0] != $moduleName or $page[0] != '')
        {
            
    /* If the current page is not found in the modules return page not found. */
            
    include ("../html/errors/404.htm");
            
    $i++;
        }

    closedir($modulesDirectory);
     
  7. Cabbit thread starter macrumors 68020

    Cabbit

    Joined:
    Jan 30, 2006
    Location:
    Scotland
    #7
    Got it now

    PHP:
    /* 
        The page Location. 
    */ 
    $page explode('/'$_GET['page']); 

    /* 
        Load the modules based on page location. 
    */ 

    /* Opens the modules directory */ 
    $modulesDirectory opendir("../application/modules/"); 

    /* Gets the modules name based on the directory name for each module. */ 
    while ($moduleName readdir($modulesDirectory))  
    {  
        if (
    $page[0] == $moduleName)
        {
            
    $currentModule $moduleName;
        } 
    }    
    if (
    $page[0] == $currentModule && $page[0] != ""

        
    /* If the current page matches a module name, return that module. */ 
        
    include ("../application/modules/".$currentModule."/".$currentModule.".php"); 
    }  
    else if (
    $page[0] == "")
    {    
        include (
    "../application/modules/example_module/example_module.php"); 
    }
    else
    {
        include (
    "../html/errors/404.htm");
    }
    closedir($modulesDirectory); 
     

Share This Page