Yves Posted January 19, 2008 Share Posted January 19, 2008 Is it possible to cache an included php file for 30 minutes (as a txt somewhere) and chache another included php file for 10 minutes without having APC installed? The thing is I don't want to cache a whole page, because there is a log in. When logged out, it showes as if you're still logged in. If I could cache included files, that would ofcourse be fabulous. Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 I'm not quite sure what you're trying to accomplish. Is it template files you wish to cache so they don't have to be parsed at every request? Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 Well, I have around 300 article categories with around 60,000 articles on my site. All 300 categories are all linked on the homepage. Each category also has the number of articles in it next to it. So you can imagine how many tables it has to go through to find the number of articles currently in the database, for each seperate category.. As of now the menu displaying the categories/subcategories is included in the index.php. Each time someone visits or revisits the homepage it takes a while to load. What I would like is to have the included (display menu) file cached for 30 minutes. After that, it can regenerate a new cache and update the content of the menu to represent to current number of articles in each category. If I could accomplish that, I would be very pleased. If I could repeat that on aother included, but this time cache for 10 minutes, my day would be made. I hope I explained well enough. !thanks Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 You could do something like this: <?php $cache_file = 'cache/menu.html'; if(filemtime($cache_file) + 30*60 > time()) { // generate the content here and store it in $menu_html; file_put_contents($cache_file, $menu_html); } else { $menu_html = file_get_contents($cache_html); } ?> You might want to expand it and make it into a class so you can do this: <?php $cache = new Cache('menu.html'); if($cache->isOlderThan(30 * 60)) { // generate content and store in $menu_html $cache->update($menu_html); } else { $menu_html = $cache->getContents(); } ?> Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 I feel generous so I decided to make the class: <?php class Cache { static protected $cache_dir; protected $contents; protected $path; public function __construct($filename) { $this->path = self::$cache_dir . $filename; if(!file_exists($filename)) { throw new Exception("Cache file '{$filename}' could not be found"); return false; } $this->contents = file_get_contents($this->path); } public function isOlderThan($seconds) { return filemtime($this->path) + 30*60 < time(); } public function update($new_content) { $this->contents = $new_content; file_put_contents($this->path, $this->contents); } public function getContents() { return $this->contents; } public function __toString() { return $this->getContents(); } static public function setCacheDir($dir) { self::$$cache_dir = $dir; } } // In another file: require_once 'library/Cache.php'; Cache::setCacheDir('/home/somebody/cache/'); // ... $cache = new Cache('menu.html'); if($cache->isOlderThan(30 * 60)) { // generate content and store in $menu_html $cache->update($menu_html); } else { $menu_html = $cache->getContents(); } ?> Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 Just spotted an error in the class. Updated: <?php class Cache { static protected $cache_dir; protected $contents; protected $path; public function __construct($filename) { $this->path = self::$cache_dir . $filename; if(!file_exists($filename)) { throw new Exception("Cache file '{$filename}' could not be found"); return false; } $this->contents = file_get_contents($this->path); } public function isOlderThan($seconds) { return filemtime($this->path) + $seconds < time(); } public function update($new_content) { $this->contents = $new_content; file_put_contents($this->path, $this->contents); } public function getContents() { return $this->contents; } public function __toString() { return $this->getContents(); } static public function setCacheDir($dir) { self::$$cache_dir = $dir; } } ?> Note: I have not tested this version or any other code I have posted in this topic. Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 I'm still trying to make the first code you wrote work. It doesn't seem to put the generated content (or html code) in cache/menu.html What I did was create the cache/ folder and menu.html file (empty) and uploaded it. Then I reloaded the homepage to see if it worked. It did display the menu so I thought it worked. However when I downloaded the menu.html file I saw it was still empty. So I'm a bit puzzled w/ that atm. EDIT: ofcourse I uploaded my edited menu.php file too. Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 Could you post the code you have? Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 sorry for taking a while <?php require_once("system/display.inc.php"); $cache_file = 'cache/menu.html'; if(filemtime($cache_file) + 1*60 > time()) { // generate the content here and store it in $menu_html; $menu_html = " <td>".echo Display($obj_db,0,left)."</td> <td width=\"25\"> </td> <td>".echo Display($obj_db,0,right)."</td> "; file_put_contents($cache_file, $menu_html); } else { $menu_html = file_get_contents($cache_html); } ?> Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 Try to change if(filemtime($cache_file) + 1*60 > time()) to if(filemtime($cache_file) - 1*60 > time() || !file_exists($cache_file)) Then delete cache/menu.html and try again. Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 Warning: filemtime() [function.filemtime]: stat failed for cache/menu.html in inc/navigation.inc.php on line 6 Warning: file_put_contents(cache/menu.html) [function.file-put-contents]: failed to open stream: No such file or directory in inc/navigation.inc.php on line 25 I think I need to add that the included file is in an inc/ folder and the cache/ folder is in the inc/ folder too Quote Link to comment Share on other sites More sharing options...
PFMaBiSmAd Posted January 19, 2008 Share Posted January 19, 2008 Caching results is fine, but make sure that there is not a bigger problem elsewhere first - Here is your performance problem - So you can imagine how many tables it has to go through to find the number of articles currently in the database, for each separate category.. By using a separate table for each category, your code is doomed to execute a query for each table present. Also, if you truly have a list of 300 categories displayed at one time on one page, you are not going to get many repeat visitors because no one wants to try and wade through that much information at one time. If the database was designed with one table for all the articles, with just a column to identify the category, it would only take one query. My guess is that the method being used to count the articles in a category is not the most efficient. Could you post just a sample of one query (or the query loop) that is getting the count(s). Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 I luckally understand what you're saying. But I had to write 'rows'. Sorry about that. So you can imagine how many rows it has to go through to find the number of articles currently in the database, for each separate category ID.. Here's the function Display($obj_db="",$ParentID,$pos) to display the menu. It's the system/display.inc.php file. If you look at my site in my signature, you can see 2 columns of menu links. The left one is generate by this code: <?php echo Display($obj_db,0,left); ?> The right one is generate by this code: <?php echo Display($obj_db,0,right); ?> <?php // Display Menu's - BEGIN // function Display($obj_db="",$ParentID,$pos) { $query = mysql_query("SELECT * FROM tblcategories WHERE intParentID = ".$ParentID." ORDER BY varCategory ASC"); $all = mysql_num_rows($query); $half = floor($all / 2); if($pos == "left") { $start = 0; if ($all % 2 == 1) { $end = $half; } if ($all % 2 == 0) { $end = $half-1; } } if($pos == "right") { if ($all % 2 == 1) { $start = $half+1; } if ($all % 2 == 0) { $start = $half; } $end = $all-1; } for($i=0; $i <= $all; $i++) { $row = mysql_fetch_array($query); if(($i >= $start )&& ($i <= $end)) { $query2 = mysql_query("SELECT * FROM tblcategories WHERE intParentID = ".$row['intID']." ORDER BY varCategory ASC"); $numchild = mysql_num_rows($query2); if($numchild>0) { echo "<div class=\"ctitle\"><a class=\"ctitle\" href=\"javascript:display('cat_".($i+1)."');\">".$row['varCategory']."</a><img src=\"images/arrow_down.gif\" alt=\"\"></div>"; echo "<div style=\"display:none;\" id=\"cat_".($i+1)."\">"; echo "<a class=\"stitle\" href=\"?Cat=".str_replace(" ","-",$row['varCategory'])."\" rel=\"nofollow\">".$row['varCategory']."</a>"; echo "<br>"; for($j=0; $j < $numchild; $j++) { $row2 = mysql_fetch_array($query2); $query3 = mysql_query("SELECT count(intID) FROM `tblarticles` WHERE intCategory = ".$row2['intID'].""); $row3 = mysql_fetch_array($query3); $numArticles = $row3['count(intID)']; if($numArticles!=0) { $numArticles = "<span class=\"stitle\">[".$numArticles."]</span>"; } else { $numArticles = ""; } echo "<a class=\"stitle\" href=\"?Cat=".str_replace(" ","-",$row['varCategory']).":".str_replace(" ","-",$row2['varCategory'])."\" rel=\"nofollow\">".$row2['varCategory']."</a>".$numArticles.""; echo "<br>"; } echo "</div>\n"; } else { echo "<div><a class=\"ctitle\" href=\"".$location."?Cat=".str_replace(" ","-",$row['varCategory'])."\" rel=\"nofollow\">".$row['varCategory']."</a> </div>"; echo "<span style=\"display:none;\" id=\"cat_".($i+1)."\"></span>\n"; } } } } // Display Menu's - END // ?> Quote Link to comment Share on other sites More sharing options...
PFMaBiSmAd Posted January 19, 2008 Share Posted January 19, 2008 By the way, there is an existing php mmcache that was designed to cache database data like your counts - http://www.php.net/manual/en/ref.memcache.php ... which was especially designed to decrease database load in dynamic web applications. Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 By the way, there is an existing php mmcache that was designed to cache database data like your counts - http://www.php.net/manual/en/ref.memcache.php ... which was especially designed to decrease database load in dynamic web applications. I knew. But I have no idea how to install such a thing. Plus I read it uses 2GB os space. Imo Danial's solution looks like it could work for what I need. All pages load fast except for the homepage. The homepage may load slow but never on every pageload. Once every 30 minutes seems suitable. Quote Link to comment Share on other sites More sharing options...
Daniel0 Posted January 19, 2008 Share Posted January 19, 2008 Try what I have attached. I tested it on my computer and it worked. [attachment deleted by admin] Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 Ok, thank you Daniel. I will have a thourough look! Quote Link to comment Share on other sites More sharing options...
Yves Posted January 19, 2008 Author Share Posted January 19, 2008 Ok. It works like a charm! Thank you soo much, Daniel. You've made my day cause I can now apply it to cache one other thing for 10 minutes instead o 30. Yeeha! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.