简单的 PHP 缓存会创建太多文件 - 需要子文件夹


Simple PHP caching creates too many files - Subfolders needed

我正在使用不久前在堆栈溢出上找到的脚本来缓存我的动态 php 页面,我对简单的解决方案非常满意,因为它只是工作,我能够将其与我的基本知识集成:D它只是php代码,没有使用.htaccess。

将创建 URL 的 MD5 哈希,以便为缓存文件创建唯一名称。但是,现在我的文件夹中有很多文件(大约 300.000),通过 ftp 打开文件夹时等待加载时间很烦人。为了减少一个文件夹中的文件数量,我正在寻找一种解决方案,使用前两个字母作为子文件夹的名称。

目前工作原理:

  • 网址: e72b0f58601e6d0c12f71a40b14101b7
  • 文件: cache/e72b0f58601e6d0c12f71a40b14101b7.html

希望的解决方案:

  • 网址: e72b0f58601e6d0c12f71a40b14101b7
  • 文件: cache/e7/e72b0f58601e6d0c12f71a40b14101b7.html

如果子文件夹不存在,则应自动创建它们。是否有人能够帮助我处理代码,或者对此解决方案有任何担忧?

考虑使用 substr-命令,但我的"实验"效果不佳。

提前感谢!

更新:感谢回复,我能够成功编辑代码。所需的更改可以在原始代码下找到

我用于缓存的代码(来源:堆栈流/http://www.sanwebe.com/2013/09/php-cache-dynamic-pages-speed-up-load-times/)

<?php
//settings
$cache_ext  = '.html'; //file extension
$cache_time     = 3600;  //Cache file expires afere these seconds (1 hour = 3600 sec)
$cache_folder   = 'cache/'; //folder to store Cache files
$ignore_pages   = array('', '');
$dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)
$cache_file     = $cache_folder.md5($dynamic_url).$cache_ext; // construct a cache file
$ignore = (in_array($dynamic_url,$ignore_pages))?true:false; //check if url is in ignore list
if (!$ignore && file_exists($cache_file) && time() - $cache_time < filemtime($cache_file)) { //check Cache exist and it's not expired.
    ob_start('ob_gzhandler'); //Turn on output buffering, "ob_gzhandler" for the compressed page with gzip.
    readfile($cache_file); //read Cache file
    echo '<!-- cached page - '.date('l jS 'of F Y h:i:s A', filemtime($cache_file)).', Page : '.$dynamic_url.' -->';
    ob_end_flush(); //Flush and turn off output buffering
    exit(); //no need to proceed further, exit the flow.
}
//Turn on output buffering with gzip compression.
ob_start('ob_gzhandler'); 
######## Your Website Content Starts Below #########
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Page to Cache</title>
    </head>
        <body>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut tellus libero.
        </body>
</html>
<?php
######## Your Website Content Ends here #########
if (!is_dir($cache_folder)) { //create a new folder if we need to
    mkdir($cache_folder);
}
if(!$ignore){
    $fp = fopen($cache_file, 'w');  //open file for writing
    fwrite($fp, ob_get_contents()); //write contents of the output buffer in Cache file
    fclose($fp); //Close file pointer
}
ob_end_flush(); //Flush and turn off output buffering
?>

如果您对解决方案感兴趣,则需要更新以下行:

源语言:

 $cache_folder   = 'cache/'; //folder to store Cache files
 $dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)

已更新(动态网址相同,但由于顺序不同,此处提及):

$dynamic_url    = 'http://'.$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']; // requested dynamic page (full url)
$cache_folder   = 'cache/'.substr(md5($dynamic_url),0,2).'/'; //folder to store Cache files

源语言:

if (!is_dir($cache_folder)) { //create a new folder if we need to
mkdir($cache_folder);
}

更新:

if (!is_dir($cache_folder)) { //create a new folder if we need to
mkdir($cache_folder, 0777, true);
}

而不是

$cache_file = $cache_folder.md5($dynamic_url).$cache_ext; // construct a cache file
...
if (!is_dir($cache_folder)) { //create a new folder recuirsively if we need to
    mkdir($cache_folder);
}

$cache_folder .= substr(md5($dynamic_url),0,2) . '/';
$cache_file = $cache_folder.md5($dynamic_url).$cache_ext;
...
if (!is_dir($cache_folder)) { //create a new folder if we need to
        mkdir($cache_folder, 0777, true);
}

这会将文件名的第一个字符添加为新的子文件夹,如果该文件夹不存在,则递归创建该文件夹。

通过FTP打开有关加载时间的文件夹时等待很烦人

我不知道FTP中的"打开文件夹"操作。当然,如果您要获得文件夹列表,则需要时间来传输数据并在客户端上呈现。它确实回避了一个问题,即通过查看文件夹可以获得什么。

可能更严重的问题是在缓存中查找单个项目并确定逐出候选项所需的时间 - 但这完全取决于数据所在的文件系统 - 并且您没有提供详细信息或这些过程的时间。

300,000 是很多文件 - 它可能是正确的数字 - 同样,您没有提供任何指示来说明这是否是预期的。OTOH 它可能指出生成缓存键的方法存在问题以及它是否适合您的应用程序。

要使用子文件夹,只需更改:

$cache_file = $cache_folder.md5($dynamic_url).$cache_ext;

$cache_file = $cache_folder.mk_hash_path($dynamic_url,$cache_folder).$cache_ext;
...
function mk_hash_path($dynamic_url,$cache_folder)
{
  md5($dynamic_url);
  $subfolders=4;
  while ($subfolders--) {
     $hash=substr($hash, -$subfolders, 1) . '/' . $hash;
  }
  if (!is_dir(dirname($cache_folder . $hash))) {
      mkdir(dirname($cache_folder . $hash,0777, true))
  }
  return $hash;
}

但是一个更聪明的想法是使用缓存反向代理。

考虑使用其他缓存机制而不是文件缓存。

您应该使用 redis 或 memcache 作为缓存存储。对于整页缓存,请选择CDN解决方案。有免费的CDN,如cloudfront。