β

wordpress的缓存插件cos-html-cache的源码解读

爱推吧 89 阅读

wordpress用上静态缓存插件cos html cache,会让你的wordpress健步如飞,下面就对这款缓存插件的源码进行解读一番,文章转自:http://mosir.org/html/y2012/review-the-source-of-cos-html-cache.html

/* config */
// 是否创建首页的静态文件
define('IS_INDEX',true);// false = do not create home page cache

/*end of config*/

define('COSVERSION','2.7.3'); // 定义插件版本

// 引入wp的文件操作函数,后面将用到其中的get_home_path
require_once(ABSPATH . 'wp-admin/includes/file.php'); 
/* end of config */
$sm_locale = get_locale(); // 获取语言环境方便后面的本地化处理

// 得到语言环境对应的本地化翻译文件,当然现在只有中文的cosbeta-zh_CN.mo 
$sm_mofile = dirname(__FILE__) . "/cosbeta-$sm_locale.mo"; 
// 加载本地化的翻译(http://codex.wordpress.org/Function_Reference/load_textdomain)
load_textdomain('cosbeta', $sm_mofile); 
// 得到博客网站的url (http://codex.wordpress.org/Option_Reference)
$cossithome = get_option('home'); 
// 获取调用链接的完整url
$script_uri = rtrim( "http://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"] ,"/"); 
$home_path = get_home_path(); // 得到wp所安装的绝对物理目录

define('SCRIPT_URI',$script_uri); // 定义调用链接
define('CosSiteHome',$cossithome); // 定义网站url
define('CosBlogPath', $home_path); // 定义网站安装物理位置
// 定义插件生效标记
define("COSMETA","<!--this is a real static html file created at ".date("Y-m-d H:i:s").
 " by cos-html-cache ".COSVERSION." -->");

// 创建静态文件的函数
function CreateHtmlFile($FilePath,$Content){ 
 // 去掉文件名中的一些非法符号
 $FilePath = preg_replace('/[ <>\'\"\r\n\t\(\)]/', '', $FilePath);

// if there is http:// $FilePath will return its bas path
 // 分隔文件路径,比如/home/xxx/xxx/xxx/xxx.html,
 // 如果是类似http://xxx.com/html/y2012/xxx.html,将传入/html/y2012/xxx.html
 // (http://cn2.php.net/manual/zh/function.explode.php)
 $dir_array = explode("/",$FilePath);

//split the FilePath
 $max_index = count($dir_array) ;
 $i = 0;
 $path = $_SERVER['DOCUMENT_ROOT']."/"; // 获取网站的根目录,比如/home/username/

while( $i < $max_index ){
 $path .= "/".$dir_array[$i]; // 把子目录一级一级加到路径上
 $path = str_replace("//","/",$path); // 如果有//则替换成/

if( $dir_array[$i] == "" ){ // 如果这目录值为空则跳过去,这个判断放在循环的最前面可能更合适
 $i ++ ;
 continue;
 }
 // 上面的代码似乎可以写得更精练

if( substr_count($path, '&') ) return true; // 如果路径中有&符号,这不好处理,不管了
 if( substr_count($path, '?') ) return true; // 有?也不管了
 if( !substr_count($path, '.htm') ){ // 如果不包含.htm,原来传了个路径进来
 //if is a directory
 // 如果路径不存在,贱之,并赋读写运行权,如果存在,那八成也是这里贱的
 if( !file_exists( $path ) ){ 
 @mkdir( $path, 0777);
 @chmod( $path, 0777 );
 }
 }
 $i ++; // 这个搞完,继续
 }

if( is_dir( $path ) ){ // 如果上面折腾完后,发现是个目录,那就是说要创建index.html
 $path = $path."/index.html";
 }
 // 如果html页面没创建完整,那还是不管算了
 if ( !strstr( strtolower($Content), '</html>' ) ) return;

//if sql error ignore...
 $fp = @fopen( $path , "w+" ); // 好了开始写了,文件在就准备覆盖内容,不在就贱之
 if( $fp ){ // 说明有权限写
 @chmod($path, 0666 ) ; // 给文件先赋个权限
 @flock($fp ,LOCK_EX ); // 锁定

// write the file。
 fwrite( $fp , $Content );// 写静态文件内容
 @flock($fp, LOCK_UN); // 解锁
 fclose($fp); // 完事
 }
}

/* read the content from output buffer */
// 在用户登录后,才会有动静,先初始化为不管,这是个非常好的习惯,
// 为了安全,一般的看不懂的东西还是躲开算了
$is_buffer = false; 
// 如果调用的是/year/y2012/xxx.html或访问的url就是网站url
if( substr_count($_SERVER['REQUEST_URI'], '.htm') || ( SCRIPT_URI == CosSiteHome) ){ 
 if( strlen( $_COOKIE['wordpress_logged_in_'.COOKIEHASH] ) < 4 ){ // 用户登录了,估计得干活了
 $is_buffer = true;
 }
 if( substr_count($_SERVER['REQUEST_URI'], '?')) $is_buffer = false; // 参数调用,躲
 if( substr_count($_SERVER['REQUEST_URI'], '../')) $is_buffer = false; // 太危险了,还是躲开好了
}

if( $is_buffer ){ // 真得得干活了
 ob_start('cos_cache_ob_callback'); // 开干
 register_shutdown_function('cos_cache_shutdown_callback'); // 高潮并结束,很快的
}

function cos_cache_ob_callback($buffer){ // 这里就是就会从wp的输出缓冲拿内容准备写到静态文件中
 // 下面一堆正则表达式,不是给一般人看的,我是一般人,所以不看了
 // 不过显然是在处理评论相关的信息
 $buffer = preg_replace('/(<\s*input[^>]+?(name=["\']author[\'"])[^>]+?value=(["\']))([^"\']+?)\3/i', '\1\3', $buffer);

$buffer = preg_replace('/(<\s*input[^>]+?value=)([\'"])[^\'"]+\2([^>]+?name=[\'"]author[\'"])/i', '\1""\3', $buffer);

$buffer = preg_replace('/(<\s*input[^>]+?(name=["\']url[\'"])[^>]+?value=(["\']))([^"\']+?)\3/i', '\1\3', $buffer);

$buffer = preg_replace('/(<\s*input[^>]+?value=)([\'"])[^\'"]+\2([^>]+?name=[\'"]url[\'"])/i', '\1""\3', $buffer);

$buffer = preg_replace('/(<\s*input[^>]+?(name=["\']email[\'"])[^>]+?value=(["\']))([^"\']+?)\3/i', '\1\3', $buffer);

$buffer = preg_replace('/(<\s*input[^>]+?value=)([\'"])[^\'"]+\2([^>]+?name=[\'"]email[\'"])/i', '\1""\3', $buffer);
 // 不是一般人看的东西结束

// 内容里没有插件做的标记,不能管
 if( !substr_count($buffer, '<!--cos-html-cache-safe-tag-->') ) return $buffer;
 // 有密码保护的文章不能管
 if( substr_count($buffer, 'post_password') > 0 ) return $buffer;//to check if post password protected 
 $wppasscookie = "wp-postpass_".COOKIEHASH;
 // 还是不能管
 if( strlen( $_COOKIE[$wppasscookie] ) > 0 ) return $buffer;//to check if post password protected 
 /* 这些内容还是放在common.js.php里的,用js去处理吧
 $comment_author_url='';
$comment_author_email='';
$comment_author='';*/


 elseif( SCRIPT_URI == CosSiteHome) {// creat homepage // 噢,首页,这个得管
 $fp = @fopen( CosBlogPath."index.bak" , "w+" ); // 先把内容弄进index.bak里
 if( $fp ){
 @flock($fp ,LOCK_EX );
 // write the file。
 fwrite( $fp , $buffer.COSMETA ); // 写,后面再加点标记说明静态文件创建成功
 @flock($fp, LOCK_UN);
 fclose($fp);
 }
 if(IS_INDEX) // 如果真得要创建首页静态文件, 就把index.bak改成index.html
 @rename(CosBlogPath."index.bak",CosBlogPath."index.html"); 
 }
 else // 其它情况,试着创建静态文件,并在后面加个标记
 CreateHtmlFile($_SERVER['REQUEST_URI'],$buffer.COSMETA );
 return $buffer;
}

function cos_cache_shutdown_callback(){ // 把静态文件真得写到物理硬盘上去,高潮过程总是很短
 ob_end_flush();
 flush();
}

if( !function_exists('DelCacheByUrl') ){
 function DelCacheByUrl($url) { // 通过url来删静态文件
 $url = CosBlogPath.str_replace( CosSiteHome,"",$url ); // 如果是完整url,就把网站给去掉
 $url = str_replace("//","/", $url ); // 把所有//替换成/
 if( file_exists( $url )){ // 文件存在
 // 如果是目录就先删里面的index.html,再删目录
 if( is_dir( $url )) {@unlink( $url."/index.html" );@rmdir($url);} 
 else @unlink( $url ); // 否则直接删静态文件
 }
 }
}

if( !function_exists('htmlCacheDel') ){
 // create single html
 function htmlCacheDel($post_ID) { // 通过文章id来删静态文件
 if( $post_ID == "" ) return true;
 $uri = get_permalink($post_ID);
 DelCacheByUrl($uri );
 }
}

if( !function_exists('htmlCacheDelNb') ){
 // delete nabour posts
 // 如果把文章删了,那也得把邻居两文章的静态文章同时删除,避免上一篇下一篇出问题
 // 不过你看出来了么,对于文章id 大于被删文章的sql语句有点小问题,新版将会解决(2.7.4版中已解决)
 function htmlCacheDelNb($post_ID) { 
 if( $post_ID == "" ) return true;

$uri = get_permalink($post_ID);
 DelCacheByUrl($uri );
 global $wpdb;
 $postRes=$wpdb->get_results("SELECT `ID` FROM `" . $wpdb->posts . "` WHERE post_status = 'publish' AND post_type='post' AND ID < ".$post_ID." ORDER BY ID DESC LIMIT 0,1;");
 $uri1 = get_permalink($postRes[0]->ID);
 DelCacheByUrl($uri1 );
 $postRes=$wpdb->get_results("SELECT `ID` FROM `" . $wpdb->posts . "` WHERE post_status = 'publish' AND post_type='post' AND ID > ".$post_ID." ORDER BY ID DESC LIMIT 0,1;");
 if( $postRes[0]->ID != '' ){
 $uri2 = get_permalink($postRes[0]->ID);
 DelCacheByUrl($uri2 );
 }
 }
}

//create index.html
if( !function_exists('createIndexHTML') ){
 // 用户编辑、删除、新建了文章,首页就会有变动了,
 // 所以得把首页静态文件先改个名,免得还是直接访问静态文件,看不到效果
 function createIndexHTML($post_ID){ 
 if( $post_ID == "" ) return true;
 //[menghao]@rename(ABSPATH."index.html",ABSPATH."index.bak");
 @rename(CosBlogPath."index.html",CosBlogPath."index.bak");//[menghao]
 }
}

if(!function_exists("htmlCacheDel_reg_admin")) { // 把删除静态文件功能加到wp的管理菜单中
 /**
 * Add the options page in the admin menu
 */
 function htmlCacheDel_reg_admin() {
 if (function_exists('add_options_page')) {
 add_options_page('html-cache-creator', 'CosHtmlCache',8, basename(__FILE__), 'cosHtmlOption');
 //add_options_page($page_title, $menu_title, $access_level, $file).
 }
 }
}

add_action('admin_menu', 'htmlCacheDel_reg_admin');

if(!function_exists("cosHtmlOption")) { // 这就是wp里cos-html-cache选项功能
function cosHtmlOption(){
 do_cos_html_cache_action();
?>
 <div class="wrap" style="padding:10px 0 0 10px;text-align:left">
 <form method="post" action="<?php echo $_SERVER["REQUEST_URI"]; ?>">
 <p>
 <?php _e("Click the button bellow to delete all the html cache files","cosbeta");?></p>
 <p><?php _e("Note:this will Not delete data from your databases","cosbeta");?></p>
 <p><?php _e("If you want to rebuild all cache files, you should delete them first,and then the cache files will be built when post or page first visited","cosbeta");?></p>

<p><b><?php _e("specify a post ID or Title to to delete the related cache file","cosbeta");?></b> <input type="text" id="cache_id" name="cache_id" value="" /> <?php _e("Leave blank if you want to delete all caches","cosbeta");?></p>
 <p><input type="submit" value="<?php _e("Delete Html Cache files","cosbeta");?>" id="htmlCacheDelbt" name="htmlCacheDelbt" onClick="return checkcacheinput(); " />
 </form>
 </div>

<SCRIPT LANGUAGE="JavaScript">
 <!--
 function checkcacheinput(){
 document.getElementById('htmlCacheDelbt').value = 'Please Wait...';
 return true;
 }
 //-->
 </SCRIPT>
<?php
 }
}
/*
end of get url
*/
// deal with rebuild or delete
function do_cos_html_cache_action(){ // 完成wp中cos-html-cache选项中删除静态文件的操作
 if( !empty($_POST['htmlCacheDelbt']) ){
 @rename(CosBlogPath."index.html",CosBlogPath."index.bak");
 @chmod( CosBlogPath."index.bak", 0666 );
 global $wpdb;
 if( $_POST['cache_id'] * 1 > 0 ){
 //delete cache by id
 DelCacheByUrl(get_permalink($_POST['cache_id']));
 $msg = __('the post cache was deleted successfully: ID=','cosbeta').$_POST['cache_id'];
 }
 else if( strlen($_POST['cache_id']) > 2 ){
 $postRes=$wpdb->get_results("SELECT `ID` FROM `" . $wpdb->posts . "` WHERE post_title like '%".$_POST['cache_id']."%' LIMIT 0,1 ");
 DelCacheByUrl( get_permalink( $postRes[0]->ID ) );
 $msg = __('the post cache was deleted successfully: Title=','cosbeta').$_POST['cache_id'];
 }
 else{
 $postRes=$wpdb->get_results("SELECT `ID` FROM `" . $wpdb->posts . "` WHERE post_status = 'publish' AND ( post_type='post' OR post_type='page' ) ORDER BY post_modified DESC ");
 foreach($postRes as $post) {
 DelCacheByUrl(get_permalink($post->ID));
 }
 $msg = __('HTML Caches were deleted successfully','cosbeta');
 }
 }
 if($msg)
 echo '<div class="updated"><strong><p>'.$msg.'</p></strong></div>';
}
$is_add_comment_is = true; // 下面是处理文章评论,增加了js来处理,相关js在common.js.php中
/*
 * with ajax comments
 */
if ( !function_exists("cos_comments_js") ){
 function cos_comments_js($postID){
 global $is_add_comment_is;
 if( $is_add_comment_is ){
 $is_add_comment_is = false;
 ?>
 <script language="JavaScript" type="text/javascript" src="/imgr?src=http%3A%2F%2Fituibar.com%2Fcache-of-wordpress-plugin-cos-html-source-reading-of-the-cache%2F%26lt%3Fphp+echo+CosSiteHome%3B%3F%26gt%3B%2Fwp-content%2Fplugins%2Fcos-html-cache%2Fcommon.js.php%3Fhash%3D%26lt%3B%3Fphp+echo+COOKIEHASH%3B%3F%26gt%3B&r=http%3A%2F%2Fituibar.com%2Fcache-of-wordpress-plugin-cos-html-source-reading-of-the-cache%2F"></script>
 <script language="JavaScript" type="text/javascript">
 //<![CDATA[
 var hash = "<?php echo COOKIEHASH;?>";
 var author_cookie = "comment_author_" + hash;
 var email_cookie = "comment_author_email_" + hash;
 var url_cookie = "comment_author_url_" + hash; 
 var adminmail = "<?php echo str_replace('@','{_}',get_option('admin_email'));?>";
 var adminurl = "<?php echo get_option('siteurl') ;?>";
 setCommForm();
 //]]>
 </script>
 <?php
 }
 }
}

function CosSafeTag(){ // 增加安全标记
 if ( is_single() || (is_home() && IS_INDEX) ) {
 echo "<!--cos-html-cache-safe-tag-->";
 }
}
function clearCommentHistory(){ // 原因查看 http://www.storyday.com/html/y2009/2270_cos-html-cache-upgrade-to-272.html
global $comment_author_url,$comment_author_email,$comment_author;
$comment_author_url='';
$comment_author_email='';
$comment_author='';
}
//add_action('comments_array','clearCommentHistory');
add_action('get_footer', 'CosSafeTag'); // 让安全标记加在footer前
add_action('comment_form', 'cos_comments_js'); // 评论特殊处理一下

/* end of ajaxcomments*/
if(IS_INDEX) add_action('publish_post', 'createIndexHTML'); // 有新文章对首页处理一下
add_action('publish_post', 'htmlCacheDelNb'); // 有新文章对相关静态文件处理一下

if(IS_INDEX) add_action('delete_post', 'createIndexHTML'); // 删除了文章也对首页处理一下
add_action('delete_post', 'htmlCacheDelNb'); // 删除文件对相关静态文件处理一下

//if comments add
add_action('edit_post', 'htmlCacheDel'); // 文章及评论有变动都要更新静态文件
if(IS_INDEX) add_action('edit_post', 'createIndexHTML'); // 可能影响首页,反正也更新一下吧

解读完成,其实在使用的过程中还会出现一个小bug:index.php文件会被修改成index.html,名字不一样,但是文件大小一样,这样会导致最新的文章直接显示首页的内容。

通过阅读东哥关于 cos-html-cache 的说明,再通过以上解读,可以发现cos-html-cache真是一个有超级高效率的wordpress缓存类插件,并且对服务器的资源占用非常小。通过这款插件,可以说让自己的网站快变成一个纯静态页面的网站了。不用一下,真是太对不起cosbeta了。

需要 特别提醒 的是:

  1. 使用前请 仔细 阅读说明
  2. cos-html-cache只会对文章和首页产生静态html文件,这对于以文章为主的博客或cms,cos-html-cache是再适合不过了。对于那些以页面为主的,除了首页,就没什么效果了。
作者:爱推吧
我爱WordPress,分享wp建站过程中的点点滴滴!
原文地址:wordpress的缓存插件cos-html-cache的源码解读, 感谢原作者分享。

发表评论