%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/main/classes/general/ |
| Current File : //home/bitrix/www/bitrix/modules/main/classes/general/cache_files.php |
<?
/*********************************************************************
Caching
*********************************************************************/
class CPHPCacheFiles
{
var $filename;
var $folder;
var $content;
var $vars;
var $TTL;
var $uniq_str;
var $initdir;
var $bStarted = false;
var $bInit = "NO";
//cache stats
var $written = false;
var $read = false;
var $path = "";
function IsAvailable()
{
return true;
}
private static function _unlink($fileName)
{
//This checks for Zend Server CE in order to supress warnings
if(function_exists('accelerator_reset'))
{
@chmod($fileName, BX_FILE_PERMISSIONS);
if(@unlink($fileName))
return true;
}
else
{
if(file_exists($fileName))
{
@chmod($fileName, BX_FILE_PERMISSIONS);
if(unlink($fileName))
return true;
}
}
return false;
}
private static function _addAgent()
{
global $APPLICATION;
static $bAgentAdded = false;
if(!$bAgentAdded)
{
$bAgentAdded = true;
$rsAgents = CAgent::GetList(array("ID"=>"DESC"), array("NAME" => "CPHPCacheFiles::DelayedDelete(%"));
if(!$rsAgents->Fetch())
{
$res = CAgent::AddAgent(
"CPHPCacheFiles::DelayedDelete();",
"main", //module
"Y", //period
1 //interval
);
if(!$res)
$APPLICATION->ResetException();
}
}
}
private static function _randomizeFile($fileName)
{
for($i = 0; $i < 99; $i++) //try to get new directory name no more than ten times
{
$suffix = rand(0, 999999);
if(!file_exists($_SERVER["DOCUMENT_ROOT"].$fileName.$suffix))
return $fileName.$suffix;
}
return "";
}
function clean($basedir, $initdir = false, $filename = false)
{
$DOCUMENT_ROOT = rtrim($_SERVER["DOCUMENT_ROOT"], "/");
if(strlen($filename))
{
$res = CPHPCacheFiles::_unlink($DOCUMENT_ROOT.$basedir.$initdir.$filename);
bx_accelerator_reset();
return $res;
}
else
{
global $DB;
$initdir = trim($initdir, "/");
if($initdir == "")
{
$sourceDir = $DOCUMENT_ROOT."/".trim($basedir, "/");
if(file_exists($sourceDir) && is_dir($sourceDir))
{
$dh = opendir($sourceDir);
if(is_resource($dh))
{
while($entry = readdir($dh))
{
if(preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $entry))
continue;
if(is_dir($sourceDir."/".$entry))
CPHPCacheFiles::clean($basedir, $entry);
elseif(is_file($sourceDir."/".$entry))
CPHPCacheFiles::_unlink($sourceDir."/".$entry);
}
}
}
}
else
{
$source = "/".trim($basedir, "/")."/".$initdir;
$source = rtrim($source, "/");
$bDelayedDelete = false;
if(!preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $source) && file_exists($DOCUMENT_ROOT.$source))
{
$target = CPHPCacheFiles::_randomizeFile($source.".~");
if($target != '')
{
if(
$DB->Query("INSERT INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG)
VALUES ('*', '*', '".$DB->ForSQL($target)."', '*')")
)
{
if(@rename($DOCUMENT_ROOT.$source, $DOCUMENT_ROOT.$target))
$bDelayedDelete = true;
}
}
}
if($bDelayedDelete)
CPHPCacheFiles::_addAgent();
else
DeleteDirFilesEx($basedir.$initdir);
bx_accelerator_reset();
}
}
}
function read(&$arAllVars, $basedir, $initdir, $filename, $TTL)
{
$fn = rtrim($_SERVER["DOCUMENT_ROOT"], "/")."/".ltrim($basedir.$initdir, "/").$filename;
if(!file_exists($fn))
return false;
$handle = null;
if(is_array($arAllVars))
{
$INCLUDE_FROM_CACHE='Y';
if(!@include($fn))
return false;
}
else
{
$handle = fopen($fn, "rb");
if(!$handle)
return false;
$datecreate = fread($handle, 2);
if($datecreate == "BX")
{
$datecreate = fread($handle, 12);
$dateexpire = fread($handle, 12);
}
else
{
$datecreate .= fread($handle, 10);
}
}
/* We suppress warning here in order not to break
the compression under Zend Server */
$this->read = @filesize($fn);
$this->path = $fn;
$res = false;
if(intval($datecreate) >= (time() - $TTL))
{
if(is_array($arAllVars))
{
$arAllVars = unserialize($ser_content);
}
else
{
$arAllVars = fread($handle, filesize($fn));
}
$res = true;
}
if($handle)
{
fclose($handle);
}
return $res;
}
function write($arAllVars, $basedir, $initdir, $filename, $TTL)
{
$folder = rtrim($_SERVER["DOCUMENT_ROOT"], "/")."/".ltrim($basedir.$initdir, "/");
$fn = $folder.$filename;
$tmp_fn = $folder.md5(mt_rand()).".tmp";
if(!CheckDirPath($fn))
return;
if($handle = fopen($tmp_fn, "wb+"))
{
if(is_array($arAllVars))
{
$contents = "<?";
$contents .= "\nif(\$INCLUDE_FROM_CACHE!='Y')return false;";
$contents .= "\n\$datecreate = '".str_pad(time(), 12, "0", STR_PAD_LEFT)."';";
$contents .= "\n\$dateexpire = '".str_pad(time() + IntVal($TTL), 12, "0", STR_PAD_LEFT)."';";
$contents .= "\n\$ser_content = '".str_replace("'", "\'", str_replace("\\", "\\\\", serialize($arAllVars)))."';";
$contents .= "\nreturn true;";
$contents .= "\n?>";
}
else
{
$contents = "BX".str_pad(time(), 12, "0", STR_PAD_LEFT).str_pad(time() + IntVal($this->TTL), 12, "0", STR_PAD_LEFT);
$contents .= $arAllVars;
}
$this->written = fwrite($handle, $contents);
$this->path = $fn;
$len = function_exists('mb_strlen')? mb_strlen($contents, 'latin1'): strlen($contents);
fclose($handle);
$this->_unlink($fn);
if($this->written === $len)
rename($tmp_fn, $fn);
$this->_unlink($tmp_fn);
}
}
function IsCacheExpired($path)
{
if(!file_exists($path))
return true;
$dateexpire = 0;
$INCLUDE_FROM_CACHE='Y';
$dfile = fopen($path, "rb");
$str_tmp = fread($dfile, 150);
fclose($dfile);
if(
preg_match("/dateexpire\s*=\s*'([\d]+)'/im", $str_tmp, $arTmp)
|| preg_match("/^BX\\d{12}(\\d{12})/", $str_tmp, $arTmp)
|| preg_match("/^(\\d{12})/", $str_tmp, $arTmp)
)
{
if(strlen($arTmp[1]) <= 0 || doubleval($arTmp[1]) < time())
return true;
}
return false;
}
function DeleteOneDir($etime = 0)
{
global $DB;
$bDeleteFromQueue = false;
$rs = $DB->Query($DB->TopSql("SELECT * from b_cache_tag WHERE TAG='*'", 1));
if($ar = $rs->Fetch())
{
$dir_name = $_SERVER["DOCUMENT_ROOT"].$ar["RELATIVE_PATH"];
if($ar["RELATIVE_PATH"] != '' && file_exists($dir_name))
{
$dh = opendir($dir_name);
if(is_resource($dh))
{
$Counter = 0;
while(($file = readdir($dh)) !== false)
{
if($file != "." && $file != "..")
{
DeleteDirFilesEx($ar["RELATIVE_PATH"]."/".$file);
$Counter++;
if(time() > $etime)
break;
}
}
closedir($dh);
if($Counter == 0)
{
rmdir($dir_name);
$bDeleteFromQueue = true;
}
}
}
else
{
$bDeleteFromQueue = true;
}
if($bDeleteFromQueue)
{
$DB->Query("
DELETE FROM b_cache_tag
WHERE SITE_ID = '".$DB->ForSQL($ar["SITE_ID"])."'
AND CACHE_SALT = '".$DB->ForSQL($ar["CACHE_SALT"])."'
AND RELATIVE_PATH = '".$DB->ForSQL($ar["RELATIVE_PATH"])."'
");
}
}
}
function DelayedDelete($count = 1, $level = 1)
{
global $DB;
$etime = time()+2;
for($i = 0; $i < $count; $i++)
{
CPHPCacheFiles::DeleteOneDir($etime);
if(time() > $etime)
break;
}
//try to adjust cache cleanup speed to cache cleanups
$rs = $DB->Query("SELECT * from b_cache_tag WHERE TAG='**'");
if($ar = $rs->Fetch())
{
$last_count = intval($ar["RELATIVE_PATH"]);
if(preg_match("/:(\\d+)$/", $ar["RELATIVE_PATH"], $m))
$last_time = intval($m[1]);
else
$last_time = 0;
}
else
{
$last_time = 0;
$last_count = 0;
}
$bWasStatRecFound = is_array($ar);
$rs = $DB->Query("SELECT count(1) CNT from b_cache_tag WHERE TAG='*'");
if($ar = $rs->Fetch())
$this_count = $ar["CNT"];
else
$this_count = 0;
$delta = $this_count - $last_count;
if($delta > 0)
{
if($last_time > 0)
$time_step = time()-$last_time;
if($time_step <= 0)
$time_step = 1;
$count = intval($this_count*$time_step/3600)+1; //Rest of the queue in an hour
}
elseif($count < 1)
{
$count = 1;
}
if($bWasStatRecFound)
{
if($last_count != $this_count)
$DB->Query("UPDATE b_cache_tag SET RELATIVE_PATH='".$this_count.":".time()."' WHERE TAG='**'");
}
else
{
$DB->Query("INSERT INTO b_cache_tag (TAG, RELATIVE_PATH) VALUES ('**', '".$this_count.":".time()."')");
}
if($this_count > 0)
return "CPHPCacheFiles::DelayedDelete(".$count.");";
else
return "";
}
}
?>