国内免费CDN 修正LayerCDN的本地化加速缓存BUG

导语:对WordPress站点的优化能做基本上都做了,Opcache+Memcached,零插件。于是想起了CDN,想自己来搭建一个免费的。其实也可以用七牛等免费的CDN,但作为写代码的人,总喜欢折腾。

在网络上找到免费资源部落的文章,发现了一个叫做LayerCDN,可以实现本地缓存,到作者的github上把它下载下来。

免费资源部落文章:https://www.freehao123.com/cdn-layer/

LayerCDN下载网址:https://github.com/oott123/Layer

LayerCDN安装报错

修改它的配置文件config.sample.inc.php,基本上没有什么改动的,因为我要本地缓存,所以在高级设定里将RUN_ENV前面的双斜杠去掉,然后将定义改为“’LOCAL’”。

config.sample.inc.php:

//Layer CDN 设定

/**********基本设定**********/
define('STATIC_URL','http://www.baidu.com/');	//源站URL
define('DOMAIN','cdn');	//使用云存储时,填写存储空间的名字;使用本地存储时,填写存储的相对路径。
define('WELCOME_DOC',TRUE);	//空请求时是否显示欢迎界面

/*********防盗链设定*********/
define('ALLOW_REGX','.*');	//设置防盗链允许的[域名]正则表达式,此表达式只匹配referer的域名部分
//define('ALLOW_REGX','^(best33\.com|.*\.best33\.com|)$');	//允许best33.com,*.best33.com,浏览器直接访问
//define('ALLOW_REGX','^(best33\.com|.*\.best33\.com)$');	//允许best33.com,*.best33.com,不允许浏览器直接访问
//define('ALLOW_REGX','^(.*)$');	//允许任意,允许浏览器访问
//define('ALLOW_REGX','^(.+)$');	//允许任意,但不允许浏览器访问

/**********进阶设定**********/
define('PURGE_KEY','purge');	//刷新缓存的密码,访问http://domain/PURGE_KEY/path/to/file来刷新缓存。
define('MIME','text/html');	//默认MIME类型,可以设为application/octet-stream则对未知项目自动弹出下载。
define('DIRECT_EXT','php|asp|htm|html');	//不进入缓存的扩展名,安全起见不要删除PHP。
define('NO_LOCATE',true);	//设置后将不进行跳转而采用read读取方式,可能会降低速度并增加流量。仅当遇到问题时启用。
define('NO_KEY',true);	//启用后将不再使用一串md5编码的key作为文件名,当想保持文件名一致时启用之。
define('NO_SECOND_FLODER',true);	//启用后将不再使用两层文件夹存储缓存,仅在本地环境、NO_KEY为假时有效。
define('STATIC_HOST','');	//可以留空,也可以在这里填写你的源站域名,而在STATIC_URL中填写IP,减少域名解析的时间。

/**********高级设定**********/
define('RUN_ENV', 'LOCAL');	//自定义运行环境(如不去掉前面的//则自动判断)可选:BAE/SAE/GCS/LOCAL 请大写
//define('CS_AK','dummy');	//自定义云存储空间的Access Token,通常不需要
//define('CS_SK','dummy');	//自定义云存储空间的Secret Token,通常不需要
国内免费CDN 修正LayerCDN的本地化加速缓存BUG
www.WordPressLeaf.com

上传到资源服务器,然后就看到了安装成功的提示,以为万事大吉,没想到这是个开始,我猜中了开头没有猜中结局。

将测试缓存文件,发现它传送过来的JS\CSS文件全部都是文本格式的,然后在服务器上,只在空间里建立了目录,根本没有保存文件。这是什么鬼,想偷一下懒不行,只能老老实实地一行一行地读代码。

代码给我们快乐呀,随便说一句,php是世界上最好的语言。:)

不服气,来辩呀。写文章很无聊,所以逗个乐子,特别是刚刚写了一半的文章因为网络问题保存失败丢失,又要开始重写,想死的心都有了。
:(

修正LayerCDN的BUG过程

带问号的文件名

当读到controller.php时发现了问题,它是截取扩展名来获取文件类型的,但这里有一个BUG,只支持标准格式的文件扩展名,例如:.png。如果遇到那种扩展名后面带问号的地址,它截取的扩展名就变成了:.js?ver=4。这样的扩展名会导致程序在识别MIME TYPE的时候出错。而现在的js、css基本上都会带上问号。那么知道问题所在了,就修改。

修改controller.php:

$ext = strtolower(substr($basename,strrpos($basename,'.')+1));
//解决有带问号的扩展名导致文件类型错误的问题,查找问号第一次出现的位置。
$ext_qm = strpos($ext,'?') ?  substr($ext,0,strpos($ext,'?')) : $ext ;

利用函数将问号前面的扩展名分离出来,这样就获得了正确的扩展名。

万事大吉了么?少年,你太天真了,这样的分离办法只能对应一种情况:.js?ver=4。对于这种:.css?ver=4.3.4,那么截取出来的扩展名就变成了:.4。

所以要从根本上解决问题,就要先分离问号。

修改controller.php:

$request = strpos($request,'?') ?  substr($request,0,strpos($request,'?')) : $request ;

这样先分离问号后,在利用扩展名获得文件类型。这时,缓存服务器传送过来的文件类型终于正确了。网页可以正常加载。

问题解决了么?没有。

国内免费CDN 修正LayerCDN的本地化加速缓存BUG
WordPressLeaf.com

返回目录路径出错

分离问号后获得文件类型虽然正确了,但是缓存服务器并没有存储文件,每次请求都是从主服务器获取的。好吧,继续来读代码。

不能在缓存服务器上保存文件,意味着写出了问题。

读到Local.php的写函数:

public function write($filename,$content){
	return file_put_contents($this->get_file($filename),$content);
	}

它进行了一次调用,继续往下读,找到了问题出在这里:

if(NO_KEY || NO_SECOND_FLODER){
	$dir = dirname($this->data_dir.$key);
	if(!is_dir($dir)){
		if(!mkdir($dir,0777,true)) die(json_encode(array('error'=>'cannot_make_dir')));
	}
	if(!$pre) return $key;
        return $dir.$key;   
}

这个return返回路径有问题,等于把路径加了两次,导致错误,例如它返回的是:/leaf/wp-content/themes/wordpressleaf/wp-content/themes/wordpressleaf/style.css,其实应该是:/leaf/wp-content/themes/wordpressleaf/style.css。
修改Local.php

return $this->data_dir.$key;   

好了,这样就能正确地获取文件,正确地写入文件了。完全没有问题了?

No,请继续看。

返回url重定向出错

我们可以看到,当第一获取文件后,会正确地返回文件,同时在缓存服务器里正确地写入文件,问题来了。当第二次获取文件时,URL就会发生重定向,导致文件获取失败。

例如,正确的ur:http://static.wordpressleaf.com/wp-content/themes/wordpressleaf/style.css。

它却跳转为:http://static.wordpressleaf.com/wp-content/themes/wordpressleaf/leaf/wp-content/themes/wordpressleaf/style.css。

Why?

这又是哪里有错了。宝宝心好累。

我先将配置文件config.sample.inc.php里的NO_LOCATE改为true,这样它会以本地read的方式来访问文件,看看是否报错。

define('NO_LOCATE',true);	//设置后将不进行跳转而采用read读取方式,可能会降低速度并增加流量。仅当遇到问题时启用。

设置后,缓存文件完全没有问题。

那就出现在url跳转方面,找到下面的语句:

public function url($filename){
    return rtrim(DOMAIN,'/').'/'.$this->get_file($filename,false);
	}

修改为:


public function url($filename){
    return '/'.rtrim(DOMAIN,'/').'/'.$this->get_file($filename,false);
	}

这样url方式访问就没有问题了。

但我不知道我这种方式是否百分百的正确,所以我就干脆用read方式来读了。那位达人可以指点一下,我的本意是要这个‘/’代表SERVER[“HTTP_HOST”] ,这样用是否百分百的正确,还是要用其他的方法?

好了,基本上本地phpCDN就没有问题了。

但在实际使用中还有一些小的问题,比如,会生成很多无缘无故的目录,无缘无故是指在别人攻击时,它会安装攻击的网址来生成一些目录,或许要加上验证才行。

那都是下一步代码工作了。

结束

这个LayerCDN,我在github上创建了一个分支,并改名为LayerLocalCDN,专注修改本地化的缓存代码。如果你感兴趣,可以在githubLayerLocalCDN下载它。或者访问这里查看它的介绍。

目前在“国内免费CDN 修正LayerCDN的本地化加速缓存BUG”上有5条评论

    1. 我自己用是服务器,没有问题。如果是空间的理论上是没有问题的,具体要你是怎么设置。这个使用是需要源站和CDN站两个站来一起设置才会有效的,源站把静态资源的域名改为指向CDN站的域名,然后CDN站需要设置源站的域名。这样打开网页时,静态资源是从CDN站读取,CDN站又从源站缓存过来的。

a进行回复 取消回复

邮箱地址不会被公开。 必填项已用*标注