PDA

查看完整版本 : 对 PHP 作Cache[转贴]


carp
2003-08-22, 10:15 AM
PHP_Cache by Dragon
--------------------------------------------------------------------------------
每个调用页面可自定义 cache 时间。如某些具体信息页面可以cache 得很久的.可以这样调用:
<?
$A_TIME = 120*60; //120分钟;
include("cache.php");
?>
经过前些天遇到的PHP search 产品 对数据库带来的严重压力,经研究,作了测试版并经过房产产品的实践证明完全可行!
现在我已整理出个比较通用的调用方法供大家使用。

使用方法:
只需要将附件中的cache.php 放到服务器上,然后在欲作cache 的PHP最头上加上: include("cache.php");

需要定义的参数:
1) $M_TIME = 5*60; //最大超时时间 ; tmp 文件允许时间
2) $A_TIME = 10*60; //Cache 时间
3) $cacheDir = "/ITC/php_cache"; // 可以是绝对也可以是相对产品的相对目录
这三个参数,

一般,$M_TIME 不必动。(主要是是避免访问超时或中断设计的)
最常定义的是 $A_TIME 页面 Cache 时间! 10*60 就是10分钟.

$cacheDir 建议一台服务器都用同一个目录.(这个目录下会自动建立了二级hash目录)
注意:比如,$cacheDir = "/ITC/php_cache"; 那么 /ITC/php_cache 一定要针对 php 程序是可写的。


优点:
技术原理很简单(通过临时文件cache页面)
操作简单;
效果明显,大大减轻服务器及数据库负担(解决访问高峰压力问题)。
自定义cache 时间.

缺点:
不能直接定义整个产品cache,(需要针对每个PHP程序加代码)
对post形式页面尚不支持.(需要改成get形式,加个NoCache参数)
对session 支持不好.


注意:对实时数据跟踪不应使用cache.



代码如下:



<?
$NC = "NoCache"; //if no cache must have this parameter.



if($$NC!=1){
$M_TIME = 2*60; //最大Wget访问超时时间 ; tmp 文件允许时间
if(!($A_TIME>0)){
$A_TIME = 10*60; //Cache 时间
}
$cacheDir = "/ITC/php_cache"; // 可以是绝对也可以是相对产品的相对目录
$debug = false;
//取得系统内部参数



//{取得当前目录产品的 cache目录
$Default_cacheDir = "cache";
if(strlen(trim($cacheDir))==0) $cacheDir = $Default_cacheDir;
$SCRIPT_FILENAME = getenv("SCRIPT_FILENAME");
$lastSlash = strrpos($SCRIPT_FILENAME,'/');
$FILE_PATH = substr($SCRIPT_FILENAME,0,$lastSlash);
if(substr($cacheDir,0,1)=='/'){
if($debug) echo "[==0]";
if(substr($cacheDir,strlen($cacheDir),1)!='/') $cacheDir=$cacheDir."/";
$FILE_PATH = $cacheDir;
}else{
if($debug) echo "[!=0]";
$FILE_PATH = $FILE_PATH."/".str_replace('/','',StripSlashes($cacheDir))."/"; // cache 目录绝对路径 like: "/ITC/product/cache/"
}



//} over
if($debug) echo $FILE_PATH."<br>";
if($debug) echo "<hr>";
//{ 取得 当前请求串 、 md5、 hash.
$q_str = getenv("QUERY_STRING");
if($debug) echo "q_str=".$q_str;
$htmlfn = Conv_QuyStr($SCRIPT_FILENAME.$q_str);// 以 /ITC/product/dir/idx.php?... 这样的输入生成唯一串
if($debug) echo "htmlfn=".$htmlfn;
//} over
$filename = $FILE_PATH.getHashPath($htmlfn).".html";
if($debug) echo "<hr size=1>";
mkdirs($filename,0744);
if($debug) echo "<hr size=1>";
$filename_tmp = $FILE_PATH.getHashPath($htmlfn).".tmp";
$QueryURL = "http://".getenv("HTTP_HOST").getenv("REQUEST_URI");
if($debug) echo $filename."==>".$filename_tmp;
if($debug) echo "<hr color=red>";



if(file_exists($filename_tmp)) { //tmp文件存在
if((date("U")-date("U",filectime($filename_tmp)))>$M_TIME) {
Generate_html($QueryURL,$filename_tmp,$filename);
}else if(!file_exists($filename)){
echo '页面正在生成… <a href=# onclick="location.reload();return(false)">重试</a>';
exit();
}



}
else { // if tmp file not exists
if(!file_exists($filename)) {
Generate_html($QueryURL,$filename_tmp,$filename);
}else if((date("U")-date("U",filectime($filename)))>$A_TIME) {
Generate_html($QueryURL,$filename_tmp,$filename);
}
}
if(!file_exists($filename)){
echo "<!--Php_cache Error:::Can not Generate_html().....please check 1)wget. 2)cache directory mod. -->";
exit();
}
include($filename);
exit();



}else{ //end $$NC!=1
//do nothing
}
function mkdirs($pathStr,$mod){
if(is_file($path) || is_dir($pathStr)) return true;
$pieces = explode("/", $pathStr);



$tmpdir = "";
for($mm=1;$mm<(count($pieces)-1);$mm++){
$tmpdir .= "/".$pieces[$mm];
if(!is_dir($tmpdir)){
mkdir($tmpdir,$mod);
}
}
return true;
}
function getHashPath($HashStr){
if(strlen($HashStr) < 4) return("");
$hs1 = substr($HashStr,-2);
// $hs2 = substr($HashStr,-4,2);
// return $hs1."/".$hs2."/".$HashStr;
return $hs1."/".$HashStr;
}



function Conv_QuyStr($Q_str) {
/*
$filename = base64_encode($Q_str);
$filename = str_replace('/','_',$filename);
*/
$filename = md5($Q_str);
return $filename;
}



function Generate_html($url,$filename_tmp,$filename) {
//处理 url 使其绕开cache 层
if(strpos($url,'?')) $url .= "&".$GLOBALS["NC"]."=1";
else $url .= "?".$GLOBALS["NC"]."=1";
//写临时文件
$fp = fopen ($filename_tmp, "w") or die("error");
$content = "in use... ";
fwrite ($fp, $content);
fclose ($fp);
$tt = "/usr/bin/wget --timeout=20 --wait=20 --tries=2 \"".$url."\" -O ".$filename_tmp." >/dev/null 2>/dev/null";
exec($tt);
copy($filename_tmp,$filename);
if(file_exists($filename_tmp)) unlink($filename_tmp);
}
//end all Cache relatived.
?>

sniper54
2003-08-22, 10:56 AM
好长,我的头,晕~~~

Cplus
2003-08-22, 12:45 PM
其实PHP应该加入这种功能

fluke
2003-08-22, 10:15 PM
这样的cache只适用于小的程序,当程序更新较快时就不能很好的满足要求了
因为整个页面的cache是较耗资源的,这时我们就需要对一个页面分部分来做cache了,因为太麻烦,我目前还未采用此方法,但实际上是可行的。