我刚刚使用Zend_Cache_Backend_static设置了静态页面缓存,以在我的应用程序中提供缓存的html文件,这非常有效。我唯一关心的是它使用$_GET参数缓存文件的方式。因为它会自动创建一个映射到所提供的URL路由的文件夹结构,所以在大量$_GET参数可能被故意附加到现有页面的情况下,这是否存在潜在的安全风险?是否达到最大目录深度或最大文件长度?
例如:目前我正在将页面缓存到/public/cache/static/
中,因此使用标准路由器/module/controller/action/param1/val1/param2/val2
或标准查询字符串/module/controller/action?param1=val1¶m2=val2
将创建以下目录结构:
/public/cache/static/module/controller/action/param1/val1/param2/val2.html
/public/cache/static/module/controller/action?param1=val1¶m2=val2.html
允许人们以这种方式创建目录结构(无论多么有限)让我有点担心。Zend_Cache_Backend_Static和相应的Zend_Cache_Frontend_Capture都必须在ini文件中设置,而不是通过Zend_Cache工厂设置,并且似乎没有任何设置选项。
这可能只是用限制$_GET变量数量的自定义路由替换默认路由器的情况吗?这可能吗?或者我需要为每条路线指定我需要的变量吗(不是世界末日,但有点限制)
更新:
因此,处理静态缓存的现有重写规则如下:
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/cached/index.html -f
RewriteRule ^/*$ cached/index.html [L]
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.html -f
RewriteRule .* cached/%{REQUEST_URI}.html [L]
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
如果请求命中静态缓存中的某个页面,它将发送该html页面。如果没有,它将击中Zend框架并生成它。
我可以在开头添加以下内容:
RewriteCond %{QUERY_STRING} S
RewriteRule [^?]+ /$0? [R=301,L]
这将完全擦除我的查询字符串。这很好,因为我仍然可以使用Zend Framework的URL路径方法传递$_GET变量(我也通过提供非常明确的路由来限制它)。但是,在不重定向的情况下可以做到这一点吗?
理想的方法是将其定义为RewriteCond,但我不确定是否可以使用mod_rewrite计算GET参数的数量。
因此,最好的解决方案可能是重定向到一个独立的php脚本,该脚本决定是否使用缓存的html文件。
<?php
if (count($_GET) >= 20) {
require __DIR__ . 'index.php';
} else {
require '/path/to/cache.html';
}
OK,因此RewriteRule剥离查询字符串将在没有重定向的情况下工作。
问题(我怀疑)是Zend_Cache_Backend_Static在某个地方使用了$_SERVER['REQUEST_URI'],因此可以访问原始文件名。我对mod_rewrite的了解非常少,我没有意识到这个值没有改变。
因此,为了防止文件和目录被大量的查询字符串创建,我不得不做以下事情:
首先针对标准查询字符串:
在我的mod_rewrite开始时剥离查询字符串,而不重定向:
RewriteCond %{QUERY_STRING} S
RewriteRule [^?]+ /$0?
在我的index.php中,我通过剥离查询字符串来更改$_SERVER['REQUEST_URI']以匹配重定向,这意味着我不再需要破解ZF:
$queryIndex = strpos($_SERVER['REQUEST_URI'], '?');
if($queryIndex !== false) {
$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $queryIndex);
}
这将阻止我的应用程序解释ANY查询字符串。因此,为了将变量传递到页面,我使用Zend Framework url路径参数。为了防止这些创建过深的缓存文件夹,我在Bootstrap:中用一些非常明确定义的路由替换了默认路由
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$route = new Zend_Controller_Router_Route(
':module/:controller/:action',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
)
);
$router->addRoute('default', $route);
$route = new Zend_Controller_Router_Route(
'article/:alias',
array(
'module' => 'default',
'controller' => 'article',
'action' => 'index',
'alias' => ''
)
);
$router->addRoute('article', $route);
在这里,我已经替换了默认路由,因此不允许使用其他参数。因此,任何需要参数的操作都必须明确设置,例如在我的第二个路由中。这意味着可能存在许多已定义的路线。值得庆幸的是,在我的特定应用程序中并非如此。
通过ZF URL路径限制路由并允许一些GET参数的一种方法是对REQUEST_URI中的斜杠数量设置限制,从而有效地限制静态页面缓存的最大目录深度(下面10)。这也可以在index.php:中更改
if(substr_count($_SERVER['REQUEST_URI'], '/') > 10) {
preg_match_all("///", $_SERVER['REQUEST_URI'] ,$capture, PREG_OFFSET_CAPTURE);
$_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 0, $capture[0][9][1]);
}